jquery - jQuery Ajax如何管理一个重定向请求?

  显示原文与译文双语对照的内容

我使用 $.post() 来调用一个使用Ajax的servlet,然后使用得到的HTML Fragment替换用户页面当前的div 元素。 但是,如果会话超时,服务器会发送重定向指令,将用户发送给登录页面。 在这种情况下,jQuery用登录页面的内容替换 div 元素,迫使用户看到一个罕见的场景。

如何使用 jQuery 1.2.6的Ajax调用管理重定向指令?

时间:

我阅读了这个问题并实现了将响应状态代码设置为 278的方法,以避免浏览器透明地处理重定向。 尽管这工作正常,但我还是有点不满,因为它有点像 hack 。

在深入挖掘之后,我放弃了这个方法并使用了 JSON 。 在这种情况下,对ajax请求的所有响应都有状态代码 200,响应主体包含一个在服务器上构建的JSON对象。 客户端上的javascript可以使用JSON对象来决定需要做什么。

我也有类似的问题。 我执行的ajax请求有 2个可能的响应: 将浏览器重定向到新页面,并将当前页面上的现有HTML表单替换为新页面的步骤。 执行这里操作的jquery代码类似于:


$.ajax({
 type:"POST",
 url: reqUrl,
 data: reqBody,
 dataType:"json",
 success: function(data, textStatus) {
 if (data.redirect) {
//data.redirect contains the string URL to redirect to
 window.location.href = data.redirect;
 }
 else {
//data.form contains the HTML for the replacement form
 $("#myform").replaceWith(data.form);
 }
 }
});

JSON对象"数据"是在服务器上构建的,有 2个成员: data.redirect 和 data.form. 我发现这种方法更好。

我解决了这个问题:

  1. 将自定义标头添加到响应:

    
    public ActionResult Index(){
     if (!HttpContext.User.Identity.IsAuthenticated)
     {
     HttpContext.Response.AddHeader("REQUIRES_AUTH","1");
     }
     return View();
    }
    
    
  2. 将一个JavaScript函数绑定到 ajaxSuccess 事件并检查标头是否存在:

    
    $(document).ajaxSuccess(function(event, request, settings) {
     if (request.getResponseHeader('REQUIRES_AUTH') === '1') {
     window.location = '/';
     }
    });
    
    

最终实现的解决方案是为Ajax调用的回调函数使用一个包装器,并在这个包装器中检查返回的HTML块是否存在特定元素。 如果找到该元素,则包装器执行重定向。 如果不是,包装器将调用转发到实际回调函数。

例如我们的包装函数类似于:



 function cbWrapper(data, funct){
 if($("#myForm", data).size()> 0)
 top.location.href="login.htm";//redirection
 else
 funct(data);
 }
 

然后,在进行Ajax调用时,我们使用了类似:



 $.post("myAjaxHandler", 
 {
 param1: foo,
 param2: bar
 },
 function(data){
 cbWrapper(data, myActualCB);
 }, 
 "html");
 

这为我们工作是因为所有Ajax调用都在一个DIV元素中返回 HTML,我们用来替换页面的一部分。 同样,我们只需要重定向到登录页面。

我喜欢timmerz的方法,稍微扭曲一下柠檬。 如果你会返回 contentTypetext/html预计 JSON时,你很可能被重定向。 在我的例子中,我只是简单地重新加载页面,它被重定向到登录页面。 哦,然后检查jqXHR状态是 200,这看起来很傻,因为你在错误函数中,右边? 否则,合法的错误案例会强制反复重新加载( 糟糕)


$.ajax(
 error: function (jqXHR, timeout, message) {
 var contentType = jqXHR.getResponseHeader("Content-Type");
 if (jqXHR.status === 200 && contentType.toLowerCase().indexOf("text/html")> = 0) {
//assume that our login has expired - reload our current page
 window.location.reload();
 }

});

使用低级 $.ajax() 调用:


$.ajax({
 url:"/yourservlet",
 data: { },
 complete: function(xmlHttp) {
//xmlHttp is a XMLHttpRquest object
 alert(xmlHttp.status);
 }
});

尝试进行重定向:


if (xmlHttp.code!= 200) {
 top.location.href = '/some/other/page';
}

我只是想分享我的方法,因为它可能会帮助某人:

我基本上包括一个javascript模块负责处理身份验证之类的也显示用户名和这种情况下处理重定向到登录页面。

我的场景:我们基本上有一个isa服务器之间听所有请求和 302和位置响应头登录页面。

在我的JavaScript模块中,我的初始方法


$(document).ajaxComplete(function(e, xhr, settings){
 if(xhr.status === 302){
//check for location header and redirect...
 }
});

( 就像这里已经提到过的) 问题是浏览器处理重定向本身所以我 ajaxComplete 调从来不叫,而是我的响应已经登录页面重定向显然是 status 200 。 问题:你如何检测成功的200响应是你实际的登录页面还是其他任意的页面?

解决办法是什么呢

由于无法捕获 302重定向响应,我在登录页面上添加了一个 LoginPage 标头,其中包含登录页面本身的url 。 在模块中,我现在监听头部并进行重定向:


if(xhr.status === 200){
 var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
 if(loginPageRedirectHeader && loginPageRedirectHeader!==""){
 window.location.replace(loginPageRedirectHeader);
 }
}

这就像魅力:。 你可能想知道为什么我在 LoginPage 头包括url。基本上因为我发现没有办法确定的url GET 造成自动从 xhr 对象位置重定向。

我认为更好的办法是利用现有的HTTP协议响应代码,特别是 401 Unauthorized

下面是我解决它的方法:

  1. 服务器端:如果会话过期,请求是 ajax 。 发送 401响应代码头
  2. 客户端:绑定到ajax事件

    
    $('body').bind('ajaxSuccess',function(event,request,settings){
    if (401 == request.status){
     window.location = '/users/login';
    }
    }).bind('ajaxError',function(event,request,settings){
    if (401 == request.status){
     window.location = '/users/login';
    }
    });
    
    

IMO这更通用,并且你没有编写一些新的自定义规范/标题。 你也不需要修改任何现有的ajax调用。

每 @Rob's 编辑:下面评论, 401 ( 用于验证错误的HTTP状态代码) 应该指标。 有关详细信息,请参阅 403禁止 vs 401未经授权的HTTP响应 。 据说有些网站框架使用 403进行身份验证和授权错误- 所以相应地适应。 感谢 Rob 。

我这样解决了这个问题:

添加一个中间件来处理响应,如果它是一个ajax请求的重定向,使用重定向url将响应更改为普通响应。


class AjaxRedirect(object):
 def process_response(self, request, response):
 if request.is_ajax():
 if type(response) == HttpResponseRedirect:
 r = HttpResponse(json.dumps({'redirect': response['Location']}))
 return r
 return response

然后在ajaxComplete中,如果响应包含重定向,它必须是重定向,所以更改浏览器的位置。


 $('body').ajaxComplete(function (e, xhr, settings) {
 if (xhr.status == 200) {
 var redirect = null;
 try {
 redirect = $.parseJSON(xhr.responseText).redirect;
 if (redirect) {
 window.location.href = redirect.replace(/?.*$/,"?next=" + window.location.pathname);
 }
 } catch (e) {
 return;
 }

 }

...