三言两语说「跨域」
什么是跨域
CORS: Cross-Origin Resource Sharing,即跨域资源共享。从安全的角度考虑,浏览器限制了从脚本内部发起跨域请求。也就是说,部分HTML标签发起的资源请求未做限制(link、script、a、img...)。由此也可以知道,跨域是浏览器的安全措施,与http请求是无关的。
什么时候会发生跨域
当请求资源的URL与当前脚本所处的URL不同时,就会发生跨域,不同之处包括三个方面的不同(protocol协议,domain域名,port端口)。
举例说明:在
http://localhost:8080/index.js
这个文件中发起了一个请求,相应的URL为
1. http://www.baidu.com/path/to/resource
2. ftp://localhost:8080/path/to/resource
3. http:localhost:8081/path/to/resource
这三个URL分别对应了三种不同的、会产生跨域请求的原因,域名不同、协议不同、端口不同。需要注意的是,资源路径本身不会带来跨域。
跨域请求的类型
简单请求
简单请求(Simple requests)需同时满足的条件:
1. 请求方法是能是:GET HEAD POST
2. Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为:
Accept
Accept-Language
Content-Language
Content-Type (需要注意额外的限制)
DPR
Downlink
Save-Data
Viewport-Width
Width
3. Content-Type 的值仅限于下列三者之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded
4. 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;
XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
5. 请求中没有使用 ReadableStream 对象。
预检请求
对那些可能对服务器数据产生副作的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。
需预检的请求(Preflighted requests)要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。
当请求满足下述任一条件时,即应首先发送预检请求:
1. 使用了下面任一 HTTP 方法:
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
2. 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
Accept
Accept-Language
Content-Language
Content-Type (需要注意额外的限制)
DPR
Downlink
Save-Data
Viewport-Width
Width
3. Content-Type 的值不属于下列之一:
application/x-www-form-urlencoded
multipart/form-data
text/plain
4. 请求中的XMLHttpRequestUpload 对象注册了任意多个事件监听器。
5. 请求中使用了ReadableStream对象。
带权限的请求(Requests with credentials)
一般而言,对于会跨域的XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。
与跨域相关的请求头和响应头
Request Headers
Origin
Access-Control-Request-Method
Access-Control-Request-Headers
Response Headers
Access-Control-Allow-Origin
Access-Control-Expose-Headers
Access-Control-Max-Age:表明该响应的有效时间,在有效时间内,浏览器无须为同一请求再次发起预检请求。
Access-Control-Allow-Credentials
Access-Control-Allow-Methods
Access-Control-Allow-Headers