Chrome 在 HTTP 302 重定向时取消 CORS XHR [英] Chrome cancels CORS XHR upon HTTP 302 redirect

查看:82
本文介绍了Chrome 在 HTTP 302 重定向时取消 CORS XHR的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

它看起来像根据 CORS 规范、GET 和 POST 请求应该透明地遵循 302 重定向.但 Chrome 正在取消我的请求.

这是执行请求的 JS:

var r = new XMLHttpRequest();r.open('GET', 'https://dev.mysite.com/rest', true);r.send();

这是应该发生的事情:

  1. 客户端:对/rest 的 XHR POST 请求
  2. 服务器:响应 HTTP 302 重定向到/rest/
  3. 客户:遵循该重定向

但是在第 2 步之后,Chrome 取消了请求.如果没有 HTTP 302,请求将完美运行.我已经确认了这一点.

当请求运行时,我在 Chrome 的网络面板中只能看到一个 XHR——一个取消的 POST 请求,没有响应头或响应正文.

用 Chrome 的 net-internals 工具调试,看到服务器有响应,之后就取消了请求.这是请求的输出:

79295: URL_REQUESThttps://dev.mysite.com/rest开始时间:2013-08-30 12:41:11.637t=1377880871637 [st= 0] +REQUEST_ALIVE [dt=13455]t=1377880871638 [st=1] URL_REQUEST_BLOCKED_ON_DELEGATE [dt=1]-->delegate = "扩展 Adblock Plus"t=1377880871639 [st= 2] +URL_REQUEST_START_JOB [dt=13453]-->load_flags = 143540480 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | ENABLE_LOAD_TIMING | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)-->方法 = "POST"-->优先级 = 2-->上传_id =0"-->url = "https://dev.mysite.com/rest"t=1377880871639 [st= 2] HTTP_CACHE_GET_BACKEND [dt=0]t=1377880871639 [st= 2] +HTTP_STREAM_REQUEST [dt=7]t=1377880871646 [st= 9] HTTP_STREAM_REQUEST_BOUND_TO_JOB-->source_dependency = 79296 (HTTP_STREAM_JOB)t=1377880871646 [st= 9] -HTTP_STREAM_REQUESTt=1377880871646 [st= 9] +HTTP_TRANSACTION_SEND_REQUEST [dt=0]t=1377880871646 [st= 9] HTTP_TRANSACTION_SEND_REQUEST_HEADERS-->GET/facultyportfolio-rest HTTP/1.1主持人:dev.liberty.edu连接:保持连接内容长度:46来源:http://localhost:8080用户代理:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.62 Safari/537.36内容类型:应用程序/json;字符集=UTF-8接受: */*引用:http://localhost:8080/ajaxtest.html接受编码:gzip、deflate、sdch接受语言:en-US,en;q=0.8t=1377880871646 [st= 9] HTTP_TRANSACTION_SEND_REQUEST_BODY-->did_merge = 真-->is_chunked = false-->长度 = 46t=1377880871646 [st= 9] -HTTP_TRANSACTION_SEND_REQUESTt=1377880871646 [st= 9] +HTTP_TRANSACTION_READ_HEADERS [dt=1001]t=1377880871646 [st= 9] HTTP_STREAM_PARSER_READ_HEADERS [dt=1000]t=1377880872646 [st= 1009] HTTP_TRANSACTION_READ_RESPONSE_HEADERS-->发现 HTTP/1.1 302日期:2013 年 8 月 30 日星期五 16:41:11 GMT服务器:Apache/2访问控制允许来源:http://localhost:8080访问控制允许凭据:true位置:https://dev.mysite.com/rest/内容语言:en-US变化:接受编码,用户代理内容编码:gzip内容长度:20连接:关闭内容类型:文本/纯文本;字符集=UTF-8t=1377880872647 [st= 1010] -HTTP_TRANSACTION_READ_HEADERSt=1377880872647 [st= 1010] +URL_REQUEST_BLOCKED_ON_DELEGATE [dt=12445]t=1377880885091 [st=13454] 取消t=1377880885092 [st=13455] -URL_REQUEST_START_JOB-->net_error = -3 (ERR_ABORTED)t=1377880885092 [st=13455] -REQUEST_ALIVE

最后,您可以看到取消",因为URL_REQUEST_BLOCKED_ON_DELEGATE".我不知道那是什么意思.但同样,如果没有 HTTP 302 重定向,则不会发生错误.

有谁知道是什么导致 Chrome 取消了这个请求?

解决方案

这里的答案是混合的,暗示代码中的某些设置等可能会解决 CORS 的重定向问题,但是 CORS 规范明确指定何时这样的 CORS重定向将失败/通过:根据规范,浏览器应该

  1. 如果对重定向资源的请求不需要飞行前检查(例如,没有自定义标头的简单 CORS 请求),则允许 3XX 重定向.见 https://www.w3.org/TR/cors/#simple-cross-origin-request-0

<块引用>

如果手动重定向标志未设置并且响应的 HTTP 状态代码为 301、302、303、307 或 308应用重定向步骤

  1. 如果对重定向资源的请求需要飞行前检查,则不允许 3XX 重定向.见 https://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0

<块引用>

如果响应的 HTTP 状态代码为 301、302、303、307 或 308应用缓存和网络错误步骤.

我在 github repo 中探索了各种 CORS 场景:https://github.com/monmohan/cors-experiment.

这个重定向失败的特定问题也可以通过这里的包轻松地单独重现:https://github.com/monmohan/cors-experiment/tree/master/issue

It looks like according to the CORS Spec, GET and POST requests should transparently follow 302 redirects. But Chrome is canceling my request.

Here's the JS that does the request:

var r = new XMLHttpRequest();
r.open('GET', 'https://dev.mysite.com/rest', true);
r.send();

Here's what should happen:

  1. Client: XHR POST request to /rest
  2. Server: responds with HTTP 302 redirect to /rest/
  3. Client: Follow that redirect

But after step 2, Chrome cancels the request. If there was no HTTP 302, the request would work perfectly. I've confirmed this.

When the request runs, I can see in Chrome's Network panel only one XHR -- a canceled POST request with no response headers or response body.

Debugging with Chrome's net-internals tool, I see that there was a response sent from the server, and after that, the request was cancelled. Here is the output of the request:

79295: URL_REQUEST
https://dev.mysite.com/rest
Start Time: 2013-08-30 12:41:11.637

t=1377880871637 [st=    0] +REQUEST_ALIVE  [dt=13455]
t=1377880871638 [st=    1]    URL_REQUEST_BLOCKED_ON_DELEGATE  [dt=1]
                              --> delegate = "extension Adblock Plus"
t=1377880871639 [st=    2]   +URL_REQUEST_START_JOB  [dt=13453]
                              --> load_flags = 143540480 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | ENABLE_LOAD_TIMING | MAYBE_USER_GESTURE | REPORT_RAW_HEADERS | VERIFY_EV_CERT)
                              --> method = "POST"
                              --> priority = 2
                              --> upload_id = "0"
                              --> url = "https://dev.mysite.com/rest"
t=1377880871639 [st=    2]      HTTP_CACHE_GET_BACKEND  [dt=0]
t=1377880871639 [st=    2]     +HTTP_STREAM_REQUEST  [dt=7]
t=1377880871646 [st=    9]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                                  --> source_dependency = 79296 (HTTP_STREAM_JOB)
t=1377880871646 [st=    9]     -HTTP_STREAM_REQUEST
t=1377880871646 [st=    9]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=0]
t=1377880871646 [st=    9]        HTTP_TRANSACTION_SEND_REQUEST_HEADERS
                                  --> GET /facultyportfolio-rest HTTP/1.1
                                      Host: dev.liberty.edu
                                      Connection: keep-alive
                                      Content-Length: 46
                                      Origin: http://localhost:8080
                                      User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.62 Safari/537.36
                                      Content-Type: application/json; charset=UTF-8
                                      Accept: */*
                                      Referer: http://localhost:8080/ajaxtest.html
                                      Accept-Encoding: gzip,deflate,sdch
                                      Accept-Language: en-US,en;q=0.8
t=1377880871646 [st=    9]        HTTP_TRANSACTION_SEND_REQUEST_BODY
                                  --> did_merge = true
                                  --> is_chunked = false
                                  --> length = 46
t=1377880871646 [st=    9]     -HTTP_TRANSACTION_SEND_REQUEST
t=1377880871646 [st=    9]     +HTTP_TRANSACTION_READ_HEADERS  [dt=1001]
t=1377880871646 [st=    9]        HTTP_STREAM_PARSER_READ_HEADERS  [dt=1000]
t=1377880872646 [st= 1009]        HTTP_TRANSACTION_READ_RESPONSE_HEADERS
                                  --> HTTP/1.1 302 Found
                                      Date: Fri, 30 Aug 2013 16:41:11 GMT
                                      Server: Apache/2
                                      Access-Control-Allow-Origin: http://localhost:8080
                                      Access-Control-Allow-Credentials: true
                                      Location: https://dev.mysite.com/rest/
                                      Content-Language: en-US
                                      Vary: Accept-Encoding,User-Agent
                                      Content-Encoding: gzip
                                      Content-Length: 20
                                      Connection: close
                                      Content-Type: text/plain; charset=UTF-8
t=1377880872647 [st= 1010]     -HTTP_TRANSACTION_READ_HEADERS
t=1377880872647 [st= 1010]     +URL_REQUEST_BLOCKED_ON_DELEGATE  [dt=12445]
t=1377880885091 [st=13454]        CANCELLED
t=1377880885092 [st=13455]   -URL_REQUEST_START_JOB
                              --> net_error = -3 (ERR_ABORTED)
t=1377880885092 [st=13455] -REQUEST_ALIVE

At the end, you can see "Cancelled" because of "URL_REQUEST_BLOCKED_ON_DELEGATE". I don't know what that means. But again, if there was no HTTP 302 redirect, the error would not occur.

Does anyone know what is causing Chrome to cancel this request?

解决方案

The answers in here are mixed, hinting on certain settings in code etc. which may solve the redirect problem with CORS, but the CORS spec clearly specifies when such CORS redirects will fail/pass : As per the spec, browsers should

  1. Allows 3XX redirect , if the request to the redirected resource doesn't require pre-flight check (simple CORS requests without custom header for example). See https://www.w3.org/TR/cors/#simple-cross-origin-request-0

If the manual redirect flag is unset and the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the redirect steps

  1. Don't allow 3XX redirect, if the request to redirected resource requires pre-flight check. See https://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0

If the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the cache and network error steps.

I have explored various CORS scenarios in github repo: https://github.com/monmohan/cors-experiment.

This specific issue with failed redirect can also be easily reproduced in isolation by the bundle here: https://github.com/monmohan/cors-experiment/tree/master/issue

这篇关于Chrome 在 HTTP 302 重定向时取消 CORS XHR的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆