https://ieftimov.com/post/deep-dive-cors-history-how-it-works-best-practices/
同源与非同源
同源与非同源可以从三个方面判断:
- 协议(http/https)
- 域名(www.example.com/example.com)
- 端口(80/443)
三者只要有一个不一样就非同源。
如:https://blog.example.com/posts/foo.html
URL | Result | Reason |
---|---|---|
https://blog.example.com/posts/bar.html |
Same | Only the path differs |
https://blog.example.com/contact.html |
Same | Only the path differs |
http://blog.example.com/posts/bar.html |
Different | Different protocol |
https://blog.example.com:8080/posts/bar.html |
Different | Different port (443by default) |
https://example.com/posts/bar.html |
Different | Different host |
同源策略
同源策略可以防止很多网络攻击,但是很难适应现在越来越多的重资源网页和单页面网页。
于是CORS应运而生。
CORS
CORS是一种控制加载子资源权限的机制。主要分为一下三种类型:
- 跨源写入cross-origin writes (cross origin post)
- 跨源嵌入 cross-origin embeds (
<img />
<video />
) - 跨源读取 cross-origin reads (cross origin ajax)
跨源写入Cross-origin writes
从非同源页面发起 Ajax Post 时,会先发一个 Ajax Option ,这是 preflight request。这一般会出现在复杂的 CORS 请求中。复杂的请求符合一下三个条件之一即可。
GET
、POST
、HEAD
方法以外的请求- 请求头(headers)中含有
Accept
、Accept-Language
、Content-Language
以外的内容 Content-Type
是application/x-www-form-urlencoded
、multipart/form-data
、text/plain
以外的值。
如果是复杂的 CORS ,这就需要在 Ajax Header 做对应的修改,如headers: {"content-type": "text/plain"}
发起 Ajax Option ,等待200返回后,再发起 Ajax Post 。但如果 Ajax Option 请求没有被正确配置,这个时候服务器会阻断这个返回,这就需要返回正确的 Ajax Option 。其中包括
Access-Control-Allow-Methods
:允许的请求方法(response.headers["Access-Control-Allow-Methods"] = "post"
)Access-Control-Allow-Headers
:允许的请求头内容(response.headers["Access-Control-Allow-``Headers"] = "Content-type"
)Access-Control-Allow-Origin
:允许的请求源(response.headers["Access-Control-Allow-``Origin"] = "https://www.google.com"
)
Ajax Option 配置正确后,还需要配置争取的 Ajax Post 返回,给 Ajax Post 配置正确的返回头(response.headers):Access-Control-Allow-Origin
。给 Ajax Post 配置允许的请求源。
这样,一个正确的 CORS 就配置完成了。
小结:跨源写入会先写入一个Ajax Option,等待Ajax Option验证通过后才允许真正的请求。如此,就需要为Ajax Option配置正确的返回头(response.headers),从而让真正的请求可以执行,真正的请求执行时,也需要为他配置正确的返回头(response.headers)。
跨源读取
跨源读取是默认阻断的。
实际上虽然请求被阻断了,但是浏览器已经正常的发送了请求并拿到了返回,只是返回被阻断了。这需要我们设置一下 Access-Control-Allow-Origin
。
优化CORS
优化 CORS 的方法是配置 Access-Control-Allow-Credentials
为 include
。