【问题标题】:How to prevent ajax requests to follow redirects using jQuery如何使用 jQuery 防止 ajax 请求跟随重定向
【发布时间】:2012-01-04 12:58:36
【问题描述】:

我使用 jQuery ajax 函数来访问 Web 服务,但是服务器并没有返回带有描述问题的状态代码的响应,而是将请求重定向到带有 200 标头的页面,以描述问题。我无法对此进行任何更改,因此我需要以某种方式在客户端上解决它。

示例: 请求转到某个未找到的 URL,因此我收到 302 重定向到另一个位置。发送了一个新请求,我收到了 200 OK,从而阻止了错误回调触发。

有什么方法可以阻止 ajax 请求跟随重定向,而是调用回调,最好是错误方法。或者,是否可以检测客户端中是否发生了重定向?

【问题讨论】:

标签: javascript jquery


【解决方案1】:

我觉得你的问题很有趣,但整个问题似乎我更多的是一个误解。至少我会尝试解释我对这个问题的理解。

静默(透明)重定向是XMLHttpRequest 规范的一部分(参见here,尤其是“...透明地遵循重定向...”)。该标准仅提到用户代理(Web 浏览器)可以阻止或通知某些类型的自动重定向,但它不是XMLHttpRequest 的一部分。它是 HTTP 客户端配置(操作系统配置)或 Web 浏览器配置的一部分。所以jQuery.ajax 没有任何选项可以阻止重定向。

您可以看到 HTTP 重定向是 HTTP 协议的一部分,而不是 XMLHttpRequest 的一部分。所以它在另一个抽象层次或网络堆栈上。例如,XMLHttpRequest 中的数据可以从 HTTP 代理或本地浏览器缓存中检索,它是 HTTP 协议的一部分。大多数服务器提供数据而不是客户端可以影响缓存。

您可以将问题中的要求与在通信过程中防止更改 Web 服务器的 IP 地址或更改 IP 路由的要求进行比较。在某些情况下,所有事情都可能很有趣,但有部分通信堆栈的另一层不能由jQuery.ajaxXMLHttpRequest 管理。

XMLHttpRequest 标准说客户端配置可以具有防止重定向的选项。如果是我更了解的“Microsoft world”,您可以查看WinHttpSetOption 函数,该函数可用于设置WINHTTP_OPTION_DISABLE_FEATURE 选项和WINHTTP_DISABLE_REDIRECTS 值。另一种方法是使用带有WINHTTP_OPTION_REDIRECT_POLICY_NEVER 值的WINHTTP_OPTION_REDIRECT_POLICY 选项。在 Windows 中可以使用的另一个功能是 WinHttpSetStatusCallback 函数,它可以设置回调函数接收一些通知,如 WINHTTP_CALLBACK_FLAG_REDIRECT

因此总体上可以实现您的要求,但解决方案可能不独立于操作系统或网络浏览器,并且不在jQuery.ajaxXMLHttpRequest 级别。

【讨论】:

  • 具有深刻见解的出色答案!我有一些 curl 的经验,你可以设置类似的标志,就像你提到的那样。我希望可以将此类指令传递给浏览器,但是从您的回答中,我了解到预期的行为将是遵循重定向,就好像初始请求已发送到服务器分配的位置一样。
  • @Jørgen:不客气!在大多数情况下,重定向根本不是问题。您没有描述使用 jQuery.ajax 的上下文以及您是否可以完全控制向其发送请求的 Web 服务器。所以很难给你其他可以真正解决你问题的建议。
  • 我不控制服务器端,恐怕。我想我最好的选择是分析或验证响应内容。
  • @Jørgen:为什么在您的情况下重定向是个问题?如果服务器临时或永久移动另一个位置上的某些页面,它可以将您的原始请求重定向到新位置。绝对没问题。管理员可以配置 Web 服务器以执行重定向,例如在服务器上的恢复操作或任何其他支持工作期间。如果您通过具有 DNS 的 URL 询问服务器,管理员可以将 IP 映射更改为另一台服务器。他可以以与重新配置 DNS 相同的方式进行 HTTP 重定向。你有什么问题?
  • 我的问题是重定向到一个通用错误页面。我知道服务器应该设置不同,但现在我需要为这种情况找到解决方案。
【解决方案2】:

我不相信这是可能的。底层库 (XHR) 透明地发出新请求。话虽如此,我在这些情况下所做的(通常是会话超时类型的交易,将我带到登录页面)是发回自定义响应标头。我还设置了一个全局 ajax 处理程序,用于检查该标头是否存在,并在存在时做出适当响应(例如,将整个页面重定向到登录屏幕)。

如果您有兴趣,这里是我必须注意的自定义标头的 jQuery 代码:

/* redirects main window when AJAX request indicates that the session has expired on the backend. */
function checkSession(event, xhr, ajaxOptions)
{
    if (xhr.readyState == 4)
    {
        if(xhr.getResponseHeader("Login-Screen") != null && xhr.getResponseHeader("Login-Screen").length)
        {
            window.location.href='sessionExpired.html'; //whatever
        }
    }
}

$(document).ajaxComplete(checkSession)

【讨论】:

  • 谢谢,我想我将不得不接受类似的方法,分析响应。
【解决方案3】:

我发现了一项功能,可以检查您的呼叫是否已被重定向。它是 xhr.state():如果它被“拒绝”,那么就会发生重定向。

成功回调示例:

request.success(function(data, textStatus, xhr)
{
    if(xhr.state() == "resolved")
    {
        //no redirection
    }
    if(xhr.state() == "rejected")
    {
        //redirection
    }
});

错误回调示例:

request.error(function(xhr, textStatus)
{
    if (xhr.state() == "rejected")
    {
        //redirection
        location.href = "loginpage";
    } else
    {
        //some other error happened
        alert("error");
    }
});

【讨论】:

  • 您回答中的提示确实帮助我们完成了工作。为了帮助其他人的注释,我们将 WebSphere Portal 的安全性与 SiteMinder 集成在一起。我们有一个需要对资源 url 进行 Ajax 调用的 portlet,当它超时时,它会发生透明重定向,但我们无法处理如何重定向到登录页面。检查 jqXHR.state() 被“拒绝”肯定有帮助。再次感谢。
  • 很棒的发现,但是可能会出现误报,因为即使一个承诺被拒绝而不仅仅是重定向时也可能触发“拒绝”状态。 jQuery 解释何时发送“拒绝”状态api.jquery.com/deferred.state
【解决方案4】:

我无法补充之前回复过的程序员的深刻智慧,但我会添加一个其他人可能会觉得有用的具体案例。

我在 SharePoint 的上下文中遇到了这个 302 静默重定向。我有一些简单的 Javascript 客户端代码可以 ping 一个 SharePoint 子站点,如果它收到 200 HTTP 响应,它会通过window.location 重新定位到该站点。如果它收到任何其他内容,它会通知用户该站点不存在。

但是,在网站存在但用户没有权限的情况下,SharePoint 会静默重定向到 AccessDenied.aspx 页面。 SharePoint 已经在服务器/场级别完成了 HTTP 401 身份验证握手 - 用户可以访问 SharePoint。但是我想使用某种数据库标志来处理对子站点的访问。静默重定向绕过了我的“else”子句,所以我不能抛出自己的错误。在我的情况下,这不是一个阻碍 - 它是一致的可预测行为。不过有点意外,在这个过程中我学到了一些关于HTTP请求的知识!

【讨论】:

    【解决方案5】:

    我对同样的事情感兴趣,找不到state() 方法mentioned by Takman 并为自己做了一些挖掘。为了让人们来这里寻找答案,以下是我的发现:

    如多次所述,您无法阻止重定向,但您可以检测到它们。根据MDN,您可以使用XMLHttpRequestObjectresponseURL,它将包含所有重定向后响应来自的最终URL。唯一需要注意的是 Internet Explorer 不支持它(Edge 有它)。由于 xhr/jqXHR 传递给 jquery 的 success/done 函数是实际 XMLHttpRequest 的扩展,因此它也应该在那里可用。

    【讨论】:

      【解决方案6】:

      虽然在XmlHttpRequests 中无法禁用位置重定向,但在使用fetch() 时是这样:

      fetch('url', {redirect: manual});
      

      【讨论】:

      • Fetch 不会告诉您重定向的 URL 是什么。您可以禁用该行为,但“redirect:manual”并不是为了让用户自己处理重定向具有名称意图。
      【解决方案7】:

      我假设你收到一个 200 响应是因为第二次没有重定向,因为 404 页面没有过期,它被保存在缓存中。也就是说第二次浏览器给你缓存中的页面。 ajax jquery 中有一个属性“缓存”。 http://api.jquery.com/jQuery.ajax/

      你应该把它写成“假”

      【讨论】:

        【解决方案8】:

        我不确定这是否适用于您的情况,但您可以编写代码来响应 AJAX 函数中的特定状态代码 -

        $.ajax({
            url: '/admin/secret/data',
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            statusCode: {
                200: function (data) {
                    alert('302: Occurred');
                    // Bind the JSON data to the UI
                },
                401: function (data) {
                    alert('401: Occurred');
                    // Handle the 401 error here.
                }
            }
        });
        

        【讨论】:

        • 我认为这不适用,因为 OP 说他总是由于后台发生重定向而获得 200 状态代码..
        【解决方案9】:

        在 ajax 请求的情况下,在请求标头中,您将拥有以下内容

        X-Requested-With    XMLHttpRequest
        

        通过服务器端的这个标准,您可以过滤请求。

        【讨论】:

        • 他想检查响应而不是请求(他已经控制)
        • 也许 Gfox 建议对于返回 3xx 的 ajax 请求没有意义,您可以过滤这种请求并返回 403 例如。当您有一个网站提供需要表单身份验证的页面并且这些页面也进行 ajax 调用并且您想将授权逻辑放在一个地方时,那么对我来说这是一个有效的答案。
        猜你喜欢
        • 2021-08-27
        • 1970-01-01
        • 2015-12-09
        • 2015-09-24
        • 2010-11-24
        • 1970-01-01
        • 2014-10-09
        • 1970-01-01
        • 2015-07-18
        相关资源
        最近更新 更多