重定向 CORS 跨域请求
TL;DR
- 非简单请求不可重定向,包括第一个preflight请求和第二个真正的请求都不行。
- 简单请求可以重定向任意多次,但如需兼容多数浏览器,只可进行一次重定向。
- 中间服务器应当同样配置相关 CORS 响应头。
中间服务器设置
当跨域请求被重定向时,中间服务器返回的 CORS 相关的响应头应当与最终服务器保持一致。 任何一级的 CORS 失败都会导致 CORS 失败。这些头字段包括Access-Control-Allow-Origin
, Access-Control-Allow-Credentials
等。
响应 preflight
的头字段包括Access-Control-Allow-Headers
, Access-Control-Allow-Methods
等。 因为 preflight 不允许重定向(见下文),所以中间服务器也就不必管这些 preflight 头字段。
如果中间服务器未设置Access-Control-Allow-Origin
,在 Chrome 中的错误信息为:
XMLHttpRequest cannot load http://mid.com:4001/redirect.
Redirect from 'http://mid.com:4001/redirect' to 'http://index.com/access-control-allow-origin-wildcard'
has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://index.com:4001' is therefore not allowed access.
如果最终服务器未设置Access-Control-Allow-Origin
,在 Chrome 中的错误信息为:
XMLHttpRequest cannot load http://index.com:4001/access-control-allow-origin-not-set.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'null' is therefore not allowed access.
Origin 变成 null 的解释见下文。
重定向preflight 请求
任何非 2xx 状态码都认为 preflight 失败
, 所以 preflight 不允许重定向。各浏览器表现一致不再赘述,可参考 W3C:
The following request rules are to be observed while making the preflight request:
If the end user cancels the request Apply the abort steps.
If the response has an HTTP status code that is not in the 2xx range Apply the network error steps.
– W3C CORS Recommandation: Cross-Origin Request with Preflight
重定向简单请求
对于简单请求浏览器会跳过 preflight 直接发送真正的请求。 该请求被重定向后浏览器会直接访问被重定向后的地址,也可以跟随多次重定向。 但重定向后请求头字段origin会被设为"null"(被认为是 privacy-sensitive context
)。 这意味着响应头中的Access-Control-Allow-Origin
需要是*
或null
(该字段不允许多个值)。
即使浏览器给简单请求设置了非简单头字段(如DNT)时,也应当继续跟随重定向且不校验响应头的DNT (因为它属于User Agent Header,
浏览器应当对此知情)。 参考 W3C 对简单请求的处理要求:
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. – W3C CORS Recommendation
OSX 下 Chrome 的行为是标准的,即使设置了DNT也会直接跟随重定向。
Safari 的怪异行为
Safari 在设置DNT字段后,会向重定向后的地址首先发起 preflight(可能是它忘记了该头部是自己设置的?)。 这一行为在桌面 Safari 的隐身模式,以及 iOS 很多浏览器中都可以观察到。 Safari 远程调试 iPhone,遇此行为调试器会崩掉(笔者试了3个 Mac+iPhone Pair)。
建议使用tcpdump或者写一个简单的 CORS 服务器来调试。 在 OPTIONS 请求中,会带有Access-Control-Request-Headers
来声明需要发送dnt。
Access-Control-Request-Headers: 'dnt, accept-language, origin'
这意味着为了 Safari 系列的浏览器(包括 iOS 平台的多数浏览器), 重定向简单 CORS 请求仍然需要实现 OPTIONS 方法(虽然我们发的只是是简单请求)。 并且在Access-Control-Allow-Headers
响应头字段添加dnt
声明。 否则 Safari 会认为 CORS 失败:
XMLHttpRequest cannot load http://index.com:4001/access-control-allow-origin-wildcard.
Request header field DNT is not allowed by Access-Control-Allow-Headers.
为了轻松地让 CORS preflight 成功,测试环境中可以简单地将请求头Access-Control-Request-Headers
的内容直接设置到响应头的Access-Control-Allow-Headers
。
重定向非简单请求
非简单请求是 preflight 成功后才发送实际的请求。 preflight 后的实际请求不允许重定向,否则会导致 CORS 跨域失败。
虽然在 Chrome 开发版中会对重定向后的地址再次发起 preflight,但该行为并不标准。 W3C Recommendation中提到真正的请求返回301, 302, 303, 307, 308都会判定为错误:
This is the actual request. Apply the make a request steps and observe the request rules below while making the request. If the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the cache and network error steps. – W3C CORS Recommendation
在 Chrome 中错误信息是Request requires preflight, which is disallowed to follow cross-origin redirect:
XMLHttpRequest cannot load http://mid.com:4001/cross-origin-redirect-with-preflight.
Redirect from 'http://mid.com:4001/cross-origin-redirect-with-preflight' to 'http://dest.com:4001/access-control-allow-origin-wildcard'
has been blocked by CORS policy: Request requires preflight,
which is disallowed to follow cross-origin redirect.
在 Safari 中的错误信息是Cross-origin redirection denied by Cross-Origin Resource Sharing policy.:
XMLHttpRequest cannot load http://mid.com:4001/redirect.
Cross-origin redirection denied by Cross-Origin Resource Sharing policy.
多次重定向的讨论
多次重定向涉及的一个关键问题是:preflight 后的请求不允许重定向。因此:
- 对于简单请求并且没有任何 preflight 的情况:浏览器会一直跟随重定向(当然 HTTP 另有规定的除外,如 POST 被 302 时),直到最后一个请求返回或者中间请求的 CORS 验证失败(比如Access-Control-Allow-Origin设置错误)。
- 对于简单请求但是浏览器会发起 preflight 的情况(比如 Safari 对 DNT 的处理):因 preflight 后重定向真正的请求会导致 CORS 失败,所以多次重定向是不可行的。
- 对于非简单请求:浏览器会直接发起 preflight,后续的重定向都是不允许的因此多次重定向不可行。
总之,如果需要兼容大多数浏览器,不论是否为简单请求都不可以多次重定向。
重定向 CORS 跨域请求的更多相关文章
- [转] 重定向 CORS 跨域请求
非简单请求不可重定向,包括第一个preflight请求和第二个真正的请求都不行. 简单请求可以重定向任意多次,但如需兼容多数浏览器,只可进行一次重定向. 中间服务器应当同样配置相关 CORS 响应头. ...
- Spring Boot Web应用开发 CORS 跨域请求支持:
Spring Boot Web应用开发 CORS 跨域请求支持: 一.Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等CORS与JSONP相比 1. JSONP只能实现 ...
- 4 伪ajax:jsonp、cors 跨域请求
一.同源策略 https://www.cnblogs.com/yuanchenqi/articles/7638956.html 同源策略(Same origin policy)是一种约定,它是浏览器最 ...
- CORS跨域请求总结
CORS跨域请求分为简单请求和复杂请求. 1. 简单请求: 满足一下两个条件的请求. (1) 请求方法是以下三种方法之一: HEAD GET POST (2)HTTP的头信息不超出以下几种字段: Ac ...
- CORS跨域请求规则以及在Spring中的实现
CORS: 通常情况下浏览器禁止AJAX从外部获取资源,因此就衍生了CORS这一标准体系,来实现跨域请求. CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origi ...
- SpringBoot配置Cors跨域请求
一.同源策略简介 同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 什么是源 源[or ...
- Java实现CORS跨域请求
问题 使用前后端分离模式开发项目时,往往会遇到这样一个问题 -- 无法跨域获取服务端数据 这是由于浏览器的同源策略导致的,目的是为了安全.在前后端分离开发模式备受青睐的今天,前端和后台项目往往会在不同 ...
- CORS——跨域请求那些事儿
在日常的项目开发时会不可避免的需要进行跨域操作,而在实际进行跨域请求时,经常会遇到类似 No 'Access-Control-Allow-Origin' header is present on th ...
- CORS跨域请求
一.问题: 服务器端代码 from flask import Flask from flask import make_response from flask import jsonify app = ...
随机推荐
- 项目搭建到Linux--实用笔记
项目搭建到Linux--实用笔记 1.启动redis 目录 /usr/local/redis/bin (我自己的目录) 启动 ./redis-server redis. ...
- StringUtil中isBlank(),idNUll,isEmpty的区别
StringUtils 方法的操作对象是 java.lang.String 类型的对象,是 JDK 提供的 String 类型操作方法的补充,并且是 null 安全的(即如果输入参数 String 为 ...
- 吴裕雄--天生自然 python开发学习笔记:pycharm无法使用ctrl+c/v复制粘贴的问题
在使用pycharm的时候发现不能正常使用ctrl+c/v进行复制粘贴,也无法使用tab键对大段代码进行整体缩进.后来发现是因为安装了vim插件的问题,在setting里找到vim插件,取消勾选即可解 ...
- mysqldump: Got error: 1449: The user specified as a definer ('user'@'%') does not exist when using LOCK TABLES
报错:一个库用mysqldump -u -p --opt --force -e --max_allowed_packet= --net_buffer_length= --databases备份时报错如 ...
- 来自ebay内部的「软件测试」学习资料,覆盖GUI、API自动化、代码级测试及性能测试等,Python等,拿走不谢!...
在软件测试领域从业蛮久了,常有人会问我: 刚入测试一年,很迷茫,觉得没啥好做的-- 测试在公司真的不受重视,我是不是去转型做开发会更好? 资深的测试架构师的发展路径是怎么样的?我平时该怎么学习? 我 ...
- 添砖加瓦:snappy无损压缩算法
一.简介 Snappy(旧称:Zippy)是Google基于LZ77的思路用C++语言编写的快速数据压缩与解压程序库,并在2011年开源.其目标并非最大压缩率或与其他压缩程序的兼容性,而是非常高的速度 ...
- 量化投资学习笔记30——《Python机器学习应用》课程笔记04
有监督学习 常用分类算法 KNN:K近邻分类器.通过计算待分类数据点,与已知数据中所有点的距离,取距离最小的前K个点,根据"少数服从多数"的原则,将这个数据点划分为出现次数最多的那 ...
- 自动清理IIS log 日志脚本
系统环境:windows server 2012 r2 IIS 版本:IIS8 操作实现清理IIS log File 脚本如下: @echo off ::自动清理IIS Log file set lo ...
- FPGA小白学习之路(1) System Verilog的概念以及与verilog的对比(转)
转自CSDN:http://blog.csdn.net/gtatcs/article/details/8970489 SystemVerilog语言简介 SystemVerilog是一种硬件描述和验证 ...
- 用 Java 实现人脸识别功能(附源码)
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...