简介
Cross-Origin Resource Sharing (CORS)
Server-Side Access Control (CORS)
什么是跨域?
跨域资源共享(CORS) 基本要点:
- 同源策略
- CORS 是一个由浏览器共同遵循的一套控制策略——同源策略,通过HTTP的Header来进行交互
- 如果header 不符合策略要求,浏览器可以拒绝javascript脚本 的http请求和拦截http 响应
- 跨域检查由浏览器自动完成,包括向请求添加Origin header、检查响应header等,javascript脚本无需关心
两种请求类型
- simple request
- preflight request,“需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
对于需要预检的请求,每次请求发一次options 和 实际请求(比如post)(url 都是一样的)。为了减少 耗时,可以通过配置 Access-Control-Max-Age
缓存 options 结果,减少options 的请求次数。 使用 Access-Control-Max-Age 来缓存 CORS 配置
后端工作
实现CORS通信,客户端是浏览器自动实现(前端开发的js脚本无需改变),nginx + 服务器代表的后端主要做以下几件事:
- 请求中的Origin header 记录了请求本身所在的域名, 服务端可据此判断是否响应该跨域请求
- 处理跨域请求后,在响应中添加跨域相关header,以通过浏览器对相关header的检查
- 服务端回应 preflight request 中的OPTIONS 请求
nginx 实现
在nginx server 配置下新增
server {
...
add_header 'Access-Control-Allow-Origin' $http_origin;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type,xx';
...
}
若该域名下已经配置了很多映射,应检查响应中新增这些header 对 其它请求的影响。 一个办法是尽量减少add_header 的作用范围
server {
location /xx{
add_header ...
add_header ...
}
}
若该域名下已存在跨域配置,则可以新增一个map配置
map $uri $originHeader {
default '*';
~正则表达式 $http_origin;
}
server {
add_header 'Access-Control-Allow-Origin' $originHeader;
add_header ...
}
代码实现
Access-Control-Allow-Origin 设置为*还是$http_origin?
Access-Control-Allow-Credentials是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名(这样浏览器才知道发送哪些cookie)。(从实践上看,这段话正确性存疑, 但应晓得有这回事)
小结
浏览器 + 后端 有一套策略(同源策略),实现起来基于一堆header。我们可以通过 设置header 来影响浏览器的行为。