Javascript 如何在jQuery Ajax调用后管理重定向请求

Javascript 如何在jQuery Ajax调用后管理重定向请求,javascript,jquery,ajax,redirect,Javascript,Jquery,Ajax,Redirect,我使用$.post()使用Ajax调用servlet,然后使用生成的HTML片段替换用户当前页面中的div元素。但是,如果会话超时,服务器将发送重定向指令,将用户发送到登录页面。在本例中,jQuery将用登录页面的内容替换div元素,迫使用户亲眼目睹一个罕见的场景 如何使用jQuery 1.2.6管理来自Ajax调用的重定向指令?使用低级的$.Ajax()调用: $.ajax({ url: "/yourservlet", data: { }, complete: function(x

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


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

使用低级的
$.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';
}
if(xhr.status === 200){
    var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
    if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
        window.location.replace(loginPageRedirectHeader);
    }
}

使用低级的
$.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';
}
if(xhr.status === 200){
    var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
    if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
        window.location.replace(loginPageRedirectHeader);
    }
}

此外,您可能希望将用户重定向到给定的in头URL。所以最后看起来是这样的:

$.ajax({
    //.... other definition
    complete:function(xmlHttp){
        if(xmlHttp.status.toString()[0]=='3'){
        top.location.href = xmlHttp.getResponseHeader('Location');
    }
});

UPD:Opps。有相同的任务,但不起作用。做这些事。找到解决方案后,我将向您展示。

此外,您可能希望将用户重定向到给定的标题URL。所以最后看起来是这样的:

$.ajax({
    //.... other definition
    complete:function(xmlHttp){
        if(xmlHttp.status.toString()[0]=='3'){
        top.location.href = xmlHttp.getResponseHeader('Location');
    }
});

UPD:Opps。有相同的任务,但不起作用。做这些事。找到解决方案后,我会向您展示。

在servlet中,您应该放置
response.setStatus(response.SC\u永久移动)
要发送重定向所需的“301”xmlHttp状态

在$.ajax函数中,您不应该使用
.toString()
函数…,只要

if(xmlHttp.status==301){
top.location.href='xxxx.jsp';
}

问题是它不是很灵活,你无法决定要重定向到哪里


通过servlet重定向应该是最好的方法。但是我仍然找不到正确的方法来做这件事。

在servlet中,您应该放置
response.setStatus(response.SC\u永久移动)
要发送重定向所需的“301”xmlHttp状态

在$.ajax函数中,您不应该使用
.toString()
函数…,只要

if(xmlHttp.status==301){
top.location.href='xxxx.jsp';
}

问题是它不是很灵活,你无法决定要重定向到哪里


通过servlet重定向应该是最好的方法。但是我仍然找不到正确的方法。没有浏览器能够正确处理301和302响应。事实上,标准甚至说他们应该“透明地”处理它们,这对于Ajax库供应商来说是一个巨大的难题。在年,我们被迫使用HTTP响应状态代码278(只是一些“未使用”的成功代码)来透明地处理来自服务器的重定向


这真的让我很恼火,如果这里有人对W3C有一些“吸引力”,我会很感激你能让W3C知道我们真的需要自己处理301和302代码…!;)

没有浏览器能够正确处理301和302响应。事实上,标准甚至说他们应该“透明地”处理它们,这对于Ajax库供应商来说是一个巨大的难题。在年,我们被迫使用HTTP响应状态代码278(只是一些“未使用”的成功代码)来透明地处理来自服务器的重定向


这真的让我很恼火,如果这里有人对W3C有一些“吸引力”,我会很感激你能让W3C知道我们真的需要自己处理301和302代码…!;)

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

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

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}
$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);
$.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);
        }
    }
});
然后,在进行Ajax调用时,我们使用了如下内容:

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}
$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);
$.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);
        }
    }
});

这对我们来说是有效的,因为所有Ajax调用总是在一个DIV元素中返回HTML,我们用它来替换页面的一部分。另外,我们只需要重定向到登录页面。

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

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

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}
$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);
$.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);
        }
    }
});
然后,在进行Ajax调用时,我们使用了如下内容:

function cbWrapper(data, funct){
    if($("#myForm", data).length > 0)
        top.location.href="login.htm";//redirection
    else
        funct(data);
}
$.post("myAjaxHandler", 
       {
        param1: foo,
        param2: bar
       },
       function(data){
           cbWrapper(data, myActualCB);
       }, 
       "html"
);
$.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);
        }
    }
});

这对我们来说是有效的,因为所有Ajax调用总是在一个DIV元素中返回HTML,我们用它来替换页面的一部分。此外,我们只需要重定向到登录页面。

我通过以下方法解决了此问题:

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

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

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

  • 我通过以下方式解决了这个问题:

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

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

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

  • 把弗拉基米尔·普鲁德尼科夫和托马斯·汉森的话放在一起:

    • 更改服务器端代码以检测它是否是XHR。如果是,则将重定向的响应代码设置为278。 在django:
    这使得浏览器将响应视为成功,并将其交给Javascript

    • 在JS中,确保表单提交是通过Ajax进行的,检查响应代码并根据需要重定向:

    把弗拉基米尔·普鲁德尼科夫和托马斯·汉森的话放在一起:

    • 更改服务器端代码以检测它是否是XHR。如果是,则将重定向的响应代码设置为278。 在django:
    这使得浏览器将响应视为成功,并将其交给Javascript

    • 在JS中,确保表单提交是通过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';
    }
    });
    
    <% HttpSession ses = request.getSession(true);
       String temp=request.getAttribute("what_you_defined"); %>
    
    function handleAjaxResponse(data, callback) {
        //Try to convert and parse object
        try {
            if (jQuery.type(data) === "string") {
                data = jQuery.parseJSON(data);
            }
            if (data.error) {
                if (data.error == 'login') {
                    window.location.reload();
                    return;
                }
                else if (data.error.length > 0) {
                    alert(data.error);
                    return;
                }
            }
        }
        catch(ex) { }
    
        if (callback) {
            callback(data);
        }
    }
    
    function submitAjaxForm(form, url, action) {
        //Lock form
        form.find('.ajax-submit').hide();
        form.find('.loader').show();
    
        $.post(url, form.serialize(), function (d) {
            //Unlock form
            form.find('.ajax-submit').show();
            form.find('.loader').hide();
    
            handleAjaxResponse(d, function (data) {
                // ... more code for if auth passes ...
            });
        });
        return false;
    }
    
    $.ajaxSetup({
        beforeSend: checkPulse,
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            document.open();
            document.write(XMLHttpRequest.responseText);
            document.close();
        }
    });
    
    [Authorize]
    public virtual void CheckPulse() {}
    
    protected void Application_EndRequest()
    {
        if (Context.Response.StatusCode == 302
            && (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
        {                
            Context.Response.StatusCode = 200;
            Context.Response.AddHeader("REQUIRES_AUTH", "1");
        }
    }
    
    function checkPulse(XMLHttpRequest) {
        var location = window.location.href;
        $.ajax({
            url: "/Controller/CheckPulse",
            type: 'GET',
            async: false,
            beforeSend: null,
            success:
                function (result, textStatus, xhr) {
                    if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
                        XMLHttpRequest.abort(); // terminate further ajax execution
                        window.location = location;
                    }
                }
        });
    }
    
    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"));
        }
    }
    
        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;
            }
        }
    
    $(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);
        }
    });
    
    $.ajaxSetup({ 
      statusCode : {
        400 : function () {
          window.location = "/";
        }
      }
    });
    
        public class MvcApplication : System.Web.HttpApplication
        {
    
        //  ...
        //  ...
    
            protected void Application_EndRequest(object sender, EventArgs e)
            {
                var app = (HttpApplication)sender;
                app.Context.Response.Headers.Add("CurrentUrl",app.Context. Request.CurrentExecutionFilePath);
            }
    
        }
    
    @Secured
    @Provider
    @Priority(Priorities.AUTHENTICATION)
    public class AuthenticationFilter implements ContainerRequestFilter {
    
        private final Logger m_logger = LoggerFactory.getLogger(AuthenticationFilter.class);
    
        public static final String COOKIE_NAME = "token_cookie"; 
    
        @Override
        public void filter(ContainerRequestContext context) throws IOException {        
            // Check if it has a cookie.
            try {
                Map<String, Cookie> cookies = context.getCookies();
    
                if (!cookies.containsKey(COOKIE_NAME)) {
                    m_logger.debug("No cookie set - redirect to login page");
                    throw new AuthenticationException();
                }
            }
            catch (AuthenticationException e) {
                context.abortWith(Response.ok("\"NEED TO AUTHENTICATE\"").type("json/application").build());
            }
        }
    }
    
    $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
        var originalSuccess = options.success;
    
        options.success = function(data) {
            if (data == "NEED TO AUTHENTICATE") {
                window.location.replace("/login.html");
            }
            else {
                originalSuccess(data);
            }
        };      
    });
    
    $.ajaxSetup({
        dataFilter: function (data, type) {
            if (data && typeof data == "string") {
                if (data.indexOf('window.location') > -1) {
                    eval(data);
                }
            }
            return data;
        }
    });
    
    public class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
    
        public CustomLoginUrlAuthenticationEntryPoint(final String loginFormUrl) {
            super(loginFormUrl);
        }
    
        // For AJAX requests for user that isn't logged in, need to return 403 status.
        // For normal requests, Spring does a (302) redirect to login.jsp which the browser handles normally.
        @Override
        public void commence(final HttpServletRequest request,
                             final HttpServletResponse response,
                             final AuthenticationException authException)
                throws IOException, ServletException {
            if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
            } else {
                super.commence(request, response, authException);
            }
        }
    }
    
      <security:http auto-config="false" use-expressions="true" entry-point-ref="customAuthEntryPoint" >
        <security:form-login login-page='/login.jsp' default-target-url='/index.jsp'                             
                             authentication-failure-url="/login.jsp?error=true"
                             />    
        <security:access-denied-handler error-page="/errorPage.jsp"/> 
        <security:logout logout-success-url="/login.jsp?logout" />
    ...
        <bean id="customAuthEntryPoint" class="com.myapp.utils.CustomLoginUrlAuthenticationEntryPoint" scope="singleton">
            <constructor-arg value="/login.jsp" />
        </bean>
    ...
    <bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache">
        <property name="requestMatcher">
          <bean class="org.springframework.security.web.util.matcher.NegatedRequestMatcher">
            <constructor-arg>
              <bean class="org.springframework.security.web.util.matcher.MediaTypeRequestMatcher">
                <constructor-arg>
                  <bean class="org.springframework.web.accept.HeaderContentNegotiationStrategy"/>
                </constructor-arg>
                <constructor-arg value="#{T(org.springframework.http.MediaType).APPLICATION_JSON}"/>
                <property name="useEquals" value="true"/>
              </bean>
            </constructor-arg>
          </bean>
        </property>
    </bean>
    
      $( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
          if ( jqxhr.status === 403 ) {
              window.location = "login.jsp";
          } else {
              if(thrownError != null) {
                  alert(thrownError);
              } else {
                  alert("error");
              }
          }
      });
    
            var str = $("#viewForm").serialize();
            $.ajax({
                url: "get_mongoDB_doc_versions.do",
                type: "post",
                data: str,
                cache: false,
                async: false,
                dataType: "json",
                success: function(data) { ... },
    //            error: function (jqXHR, textStatus, errorStr) {
    //                 if(textStatus != null)
    //                     alert(textStatus);
    //                 else if(errorStr != null)
    //                     alert(errorStr);
    //                 else
    //                     alert("error");
    //            }
            });
    
    status: 204 No Content
    x-status: 308 Document Redirect
    x-location: /login.html