我使用$.post()使用Ajax调用servlet,然后使用生成的HTML片段替换用户当前页面中的div元素。但是,如果会话超时,服务器将发送重定向指令,将用户发送到登录页面。在本例中,jQuery用登录页面的内容替换div元素,迫使用户的眼睛看到一个罕见的场景。

如何使用jQuery1.2.6管理Ajax调用的重定向指令?


当前回答

如果您使用的是Spring Security,答案似乎对人们有用,但我发现扩展LoginUrlAuthenticationEntryPoint并添加特定代码来处理AJAX更为健壮。大多数示例拦截所有重定向,而不仅仅是身份验证失败。这对于我所从事的项目来说是不可取的。如果不希望缓存失败的AJAX请求,您可能会发现还需要扩展ExceptionTranslationFilter并重写“sendStartAuthentication”方法以删除缓存步骤。

示例AjaxAwareAuthenticationEntryPoint:

public class AjaxAwareAuthenticationEntryPoint extends
    LoginUrlAuthenticationEntryPoint {

    public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
        super(loginUrl);
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        if (isAjax(request)) {
            response.sendError(HttpStatus.UNAUTHORIZED.value(), "Please re-authenticate yourself");
        } else {
        super.commence(request, response, authException);
        }
    }

    public static boolean isAjax(HttpServletRequest request) {
        return request != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
    }
}

来源:1, 2

其他回答

大多数给定的解决方案都使用一种变通方法,使用额外的头或不合适的HTTP代码。这些解决方案很可能会奏效,但感觉有点“粗糙”。我想出了另一个解决方案。

我们使用的WIF被配置为在401响应上重定向(passiveRedirectEnabled=“true”)。重定向在处理正常请求时是有用的,但对AJAX请求不起作用(因为浏览器不会执行302/重定向)。

使用global.asax中的以下代码,可以禁用AJAX请求的重定向:

    void WSFederationAuthenticationModule_AuthorizationFailed(object sender, AuthorizationFailedEventArgs e)
    {
        string requestedWithHeader = HttpContext.Current.Request.Headers["X-Requested-With"];

        if (!string.IsNullOrEmpty(requestedWithHeader) && requestedWithHeader.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
        {
            e.RedirectToIdentityProvider = false;
        }
    }

这允许您为AJAX请求返回401个响应,然后javascript可以通过重新加载页面来处理这些响应。重新加载页面将抛出一个401,由WIF处理(WIF将用户重定向到登录页面)。

处理401错误的示例javascript:

$(document).ajaxError(function (event, jqxhr, settings, exception) {

    if (jqxhr.status == 401) { //Forbidden, go to login
        //Use a reload, WIF will redirect to Login
        location.reload(true);
    }
});

我阅读了这个问题,并实现了所述的将响应HTTP状态代码设置为278的方法,以避免浏览器透明地处理重定向。尽管这起了作用,但我还是有点不满意,因为这有点黑客。

在深入研究之后,我放弃了这种方法,改用JSON。在这种情况下,对AJAX请求的所有响应都具有状态代码200,并且响应的主体包含在服务器上构造的JSON对象。然后,客户端上的JavaScript可以使用JSON对象来决定需要做什么。

我有一个和你类似的问题。我执行一个AJAX请求,它有两种可能的响应:一种是将浏览器重定向到新页面,另一种是用新页面替换当前页面上的现有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对象“data”在服务器上构造为有两个成员:data.redirect和data.form。我发现这种方法要好得多。

如果您使用的是Spring Security,答案似乎对人们有用,但我发现扩展LoginUrlAuthenticationEntryPoint并添加特定代码来处理AJAX更为健壮。大多数示例拦截所有重定向,而不仅仅是身份验证失败。这对于我所从事的项目来说是不可取的。如果不希望缓存失败的AJAX请求,您可能会发现还需要扩展ExceptionTranslationFilter并重写“sendStartAuthentication”方法以删除缓存步骤。

示例AjaxAwareAuthenticationEntryPoint:

public class AjaxAwareAuthenticationEntryPoint extends
    LoginUrlAuthenticationEntryPoint {

    public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
        super(loginUrl);
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        if (isAjax(request)) {
            response.sendError(HttpStatus.UNAUTHORIZED.value(), "Please re-authenticate yourself");
        } else {
        super.commence(request, response, authException);
        }
    }

    public static boolean isAjax(HttpServletRequest request) {
        return request != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
    }
}

来源:1, 2

作为ajax的替代,正在开发一个新的Fetch API,它允许手动重定向处理。您需要检查当前的浏览器支持是否足以满足您的需要。

使用低级$.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';
}