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

IT技术 javascript jquery ajax redirect
2021-01-06 16:37:12

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

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

6个回答

我阅读了这个问题并实现了关于将响应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 对象“数据”在服务器上构造为具有 2 个成员:data.redirectdata.form. 我发现这种方法要好得多。

stackoverflow.com/questions/503093/中的解决方案所述……最好使用window.location.replace(data.redirect); 比 window.location.href = data.redirect;
2021-02-22 16:37:12

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

  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 = '/';
        }
    });
    
请注意在重定向后的响应中设置标头。如本页其他答案所述,重定向可能对 ajaxSucces 处理程序是透明的。因此,我在登录页面的 GET 响应中包含了标头(最终并且仅在我的场景中触发了 ajaxSuccess)。
2021-02-07 16:37:12
在很多情况下都可以,但是如果您的框架处理授权呢?
2021-02-11 16:37:12
我只是这样做了,发现我需要 ajaxComplete 在我使用 $.get() 函数的地方,除了 200 之外的任何状态都没有触发。事实上,我可能只是绑定到 ajaxError 而已。有关更多详细信息,请参阅下面我的回答。
2021-02-14 16:37:12
多么棒的解决方案。我喜欢一站式解决方案的想法。我需要检查 403 状态,但我可以为此使用 ajaxSuccess 绑定在 body 上(这正是我真正想要的。)谢谢。
2021-02-17 16:37:12
我喜欢标题方法,但也认为 - 就像@mwoods79 - 不应该重复重定向到哪里的知识。我通过添加标题 REDIRECT_LOCATION 而不是布尔值来解决这个问题。
2021-02-27 16:37:12

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

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

浏览器从第一天起就透明地处理它。什么是ajax请求?当您希望浏览器执行请求并返回结果时。什么,你想要的是一个特殊情况:“...返回的结果,但在重定向的情况下,不返回的结果。” 作为库开发人员,这可能会惹恼您,因为您正在尝试处理一般情况,改变浏览器的工作方式。但既然你这样做了,你应该期待烦恼。
2021-02-11 16:37:12
它不是已经透明地处理它们了吗?如果资源已经移动,透明地处理它意味着在提供的 URL 上重复请求。这就是我对使用 XMLHttpRequest API 的期望。
2021-02-12 16:37:12
@PhilippeRathé 同意。透明处理正是我想要的。我不知道为什么它被认为是不好的。
2021-02-18 16:37:12
@smwikipedia 安排重定向主要部分中的标记而不重定向页面。
2021-02-27 16:37:12
我认为 278 应该成为官方 HTTP 规范的一部分。
2021-03-02 16:37:12

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

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

function cbWrapper(data, funct){
    if($("#myForm", data).length > 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。此外,我们只需要重定向到登录页面。

请注意,这可以缩短为 function cbWrapper(funct) { return function(data) { if($("#myForm", data).size() > 0) top.location.href="login"; 其他功能(数据);} } 。然后在调用 .post 时只需要 cbWrapper(myActualCB)。是的,注释中的代码一团糟,但应该注意:)
2021-02-18 16:37:12
size 已折旧,因此您可以在此处使用 .length 代替 size
2021-03-04 16:37:12

我喜欢 Timmerz 的方法,稍微加一点柠檬。如果你有机会返回的contentType的text / html,当你期待JSON,你是最有可能被重定向。就我而言,我只是简单地重新加载页面,然后它就会被重定向到登录页面。哦,检查 jqXHR 状态是否为 200,这看起来很傻,因为您在错误函数中,对吧?否则,合法的错误情况将强制迭代重新加载(oop)

$.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();
    }

});
我检查了状态 401,然后重定向。像冠军一样工作。
2021-02-15 16:37:12
非常感谢布赖恩,您的回答最适合我的情况,尽管我希望是否有更安全的检查,例如比较重定向到哪个 url/页面而不是简单的“内容类型”检查。我无法找到从 jqXHR 对象重定向到的页面。
2021-03-07 16:37:12