一 同源策略
浏览器处于对安全方面的考虑,不允许跨域调用其他域下的资源。当 协议,域名,端口相同的时候才算是同一个域名,否则均认为需要做跨域的处理。
可以通过以下脚本开启一个运行跨域的浏览器:
open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security |
二 CORS:
简单请求(simple request)
- 请求方法是三种之一:HEAD、GET、POST
- HTTP的头信息不超出以下几种字段:Accept、Accept-Language、Content-Language、Last-Event-ID
- Content-Type 只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain
2.1 基本流程
- 浏览器发现是跨域的话,会自动加上
Origin
字段; - 如果
Origin
指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin
字段,会抛出一个错误,可以被 XMLHttpRequest 的 onerror 回调函数捕获。但这种错误无法通过状态码识别,因为 HTTP 回应的状态码有可能是 200; - 如果
Origin
指定的域名在许可范围内,服务器返回的响应会多出几个头信息字段。
Access-Control-Allow-Origin: http://api.bob.com //该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个 *,表示接受任意域名的请求。 |
2.2 withCredentials 属性
CORS 请求默认不发送 cookie 和 HTTP 认证信息。如果要把 cookie 发到服务器,一方面要服务器同意,指定 Access-Control-Allow-Credentials
字段:
Access-Control-Allow-Credentials: true |
另一方面,开发者必须在 Ajax 请求中打开 withCredentials 属性:
var xhr = new XMLHttpRequest(); |
Attention: 如果要发送 cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,cookie 依然遵循同源政策,只有用服务器域名设置的 cookie 才会上传,其他域名的 cookie 并不会上传,且(跨源)原网页代码中的 document.cookie 也无法读取服务器域名下的 cookie。
非简单请求(not-so-simple request)
- 方法:PUT 或 DELETE
- Content-Type:application/json
预检请求
如果浏览器发现这是一个非简单请求,就自动发出一个「预检请求(preflight)」。浏览器先询问服务器:当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 方法和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求否则就报错。「预检」请求用的请求方法是 OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是 Origin
,表示请求来自哪个源。
除了Origin
字段,预检请求的头信息包括两个特殊字段:Access-Control-Request-Method
、Access-Control-Request-Headers
预检响应
AAccess-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Max-Age
三 JSONP(Json with padding)
w3schools: https://www.w3schools.com/js/js_json_jsonp.asp
在进行 Ajax 请求时,由于同源策略不能进行跨域请求,而<script>
标签的 src 属性却可以加载跨域的 JavaScript 脚本,JSONP 就是利用这一特性实现的。与普通的 Ajax 请求不同,在使用 JSONP 进行跨域请求时,服务器不再返回 JSON 格式的数据,而是返回一段调用某个函数的 JavaScript 代码,在 src 属性中调用来实现跨域。
JSONP 的优点是兼容性好,在一些老旧的浏览器种也可以运行,但它的缺点也非常明显:
- 只能进行 GET 请求;
- XSS 攻击