浏览器同源策略下的跨域访问解决方案
- 如果站点 A 允许站点 B 的脚本访问其资源, 必须在 HTTP 响应中显示的告知浏览器:站点 B 是被允许的
- 访问站点 A 的请求,浏览器应告知该请求来自站点 B
- 站点 A 的响应中,应明确哪些跨域请求是被允许的
简单请求的跨域访问
简单请求的特点
- GET/HEAD/POST 方法之一
- 仅能使用 CORS 安全的头部: Accept、Accept-Language、Content-Language、Content-Type
- Content-Type 值只能是: test/plain、multipart/form-data、application/x-www/form-urlencoded 三者其中之一
具体步骤
- 请求中携带 Origin 头部告知来自哪个域
- 响应中携带 Access-Control-Allow-Origin 头部表示允许哪些域
- 浏览器放行
PS:可能你会觉得响应中返回 Access-Control-Allow-Origin 有点多余,因为 Client 已经告诉 Server 我来自哪个域了,Server就可以决定接不接受这个域的访问了。为什么还要反过来告诉 Client 允许哪些域访问呢。
其实限制访问都是 Client 端做限制的, Server 是不做任何限制的,即使 Client 不传 Origin头部, Server 也还是会发给 Client 响应的。浏览器根据响应的 Access-Control-Allow-Origin,判断当前页面所在的域名是否与之匹配,如果不匹配浏览器就不会去渲染相应的请求。
在 Nginx 中加一个头部即可:
.
.
server {
.
.
localtion / {
add_header Access-Control-Allow-Origin '*';
}
.
.
}
复杂请求的跨域访问
预检请求
-
预检请求头部
Origin 一个页面的资源可能来自多个域名,在 AJAX 等子请求中标明来源于某个域名下的脚本,以通过服务器的安全校验
Access-Control-Request-Mothod 在 preflight 预检请求(OPTIONS)中,告知服务器接下来请求会使用哪些方法
Access-Control-Request-Headers 在 preflight 预检请求(OPTIONS)中,告知服务器接下来请求会传递哪些头部 -
预检请求响应
Access-Control-Allow-Mothods 在 preflight 预检请求(OPTIONS)中,告知客户端后续请求允许使用的方法
Access-Control-Allow-Headers 在 preflight 预检请求(OPTIONS)中,告知客户端后续请求允许携带的头部
Access-Control-Max-Age 告知客户端该响应的信息可以缓存多久
Access-Control-Expose-Headers 告知浏览器哪些响应头可以供客户端使用,默认只有 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma 可供使用
Access-Control-Allow-Origin 告知浏览器允许哪些域访问当前资源,*表示允许所有域。为避免缓存错乱,响应中需要携带 Vary:Origin (ajax请求也可能会被缓存,用来区分来自不同的域的ajax)
Access-Control-Allow-Credentials 告知浏览器是否可以将 Credentials 暴露给客户端使用, Credentials 包含 cookie、authorization 类头部、TLS证书等。
在 Nginx 中加入允许的头部即可:
.
.
server {
.
.
localtion / {
add_header Access-Control-Allow-Origin '*';
add_header Access-Control-Allow-Headers 'Origin, X-Requested-With, Content-Type, Accept';
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS';
}
.
.
}