CORS的英文全称是"Cross-Origin Resource Sharing"。代表“跨域资源共享”,是一种用于在Web浏览器和Web服务器之间共享跨域资源的机制。跨域资源是指来自不同域的网页上的资源,如字体,图像,脚本和样式表等。CORS允许网站服务器提供一组规则,以确定哪些网站可以访问其资源。
1.什么是跨域请求
跨域请求是指从一个Web页面发出的请求,而且其目标资源与当前页面不同源。
同源是指协议、域名和端口号都相同,而不仅仅是域名相同。
如果使用的协议、端口或域名有一个不同,它们就被视为不同源,默认不可以进行跨域访问。
2.预检(Preflight)请求
顾名思义,预检请求用来检查实际请求是否安全可行,确保接下来的实际请求不会引起安全问题。
浏览器会在发送预检请求之后等待响应,只有当服务器允许时,才会发送实际请求。
2.1 什么情况下会触发预检请求
预检请求的反义词是简单请求,我们可以看下简单请求的判断标准
若请求满足所有下述条件,则该请求是简单请求:
请求方法使用下列方法之一:
-
GET
-
HEAD
-
POST
允许手动设置的标头字段为:
-
Accept
-
Accept-Language
-
Content-Language
-
Content-Type(需要注意额外的限制)
-
Range(只允许简单的范围标头值 如 bytes=256- 或 bytes=127-255)
Content-Type 标头的值仅限于下列三者之一:
-
text/plain
-
multipart/form-data
-
application/x-www-form-urlencoded
XMLHttpRequest.upload 对象属性上没有注册任何事件监听器
也就是说,没有调用 xhr.upload.addEventListener(),以监听上传请求。
请求中没有使用 ReadableStream 对象。
如果不满足上述任何一个条件,都会触发预检请求
2.2 预检请求的CORS处理
在CORS中,预检请求的目的是用于检查跨域请求是否安全、可行。
预检请求是在正式的跨域请求之前发起的一次探测,用于告知服务器,实际发送的跨域请求是否合法。
因此,对于预检请求的处理,需要服务器端进行相应的配置。
预检请求的处理步骤如下:
-
浏览器会先发送一个OPTIONS请求(预检请求),包含了实际发送的跨域请求所需要的一些头信息,比如请求方法、请求头等。
-
服务器收到后,会根据请求头中的信息进行判断,判断跨域请求是否安全可行。
-
如果跨域请求合法,服务器会返回带有特定CORS响应头的响应,告知浏览器实际发送的跨域请求是合法的。
-
浏览器接收到服务器的响应后,会检查响应头中的"CORS"信息。如果CORS响应头合法,则浏览器会发送实际的跨域请求,否则会抛出跨域错误,请求无法成功。
2.3 非预检请求的CORS处理
对于非预检请求,CORS会按照以下规则进行处理:
-
如果响应头中没有包含"Access-Control-Allow-Origin",或者它的值不包含当前域名,则浏览器会抛出一个跨域错误,请求无法成功。
-
如果响应头中包含"Access-Control-Expose-Headers",则该响应头中列出的头信息可以被前端JavaScript访问。否则,这些头信息将被浏览器拦截,无法被前端JavaScript访问。
-
需要注意的是,虽然非预检请求不需要发送OPTIONS请求,但仍然需要服务器返回合法的CORS响应头信息。
3.跨域有关的响应头
下面列出了和跨域有关的响应头:
-
Access-Control-Allow-Origin:哪些源可以访问该资源。"*"表示所有的源都可以访问该资源。
-
Access-Control-Allow-Credentials:是否允许发送Cookie。
-
Access-Control-Expose-Headers:哪些响应头可以被前端JavaScript访问。默认情况下,不允许访问
-
Access-Control-Allow-Methods:哪些HTTP请求方法允许跨域访问。默认情况下,只允许GET、HEAD、POST方法。
-
Access-Control-Allow-Headers:允许的请求头信息。默认情况下,只允许常见的请求头,Accept、Accept-Language、Content-Language、Content-Type。
-
Access-Control-Max-Age:预检请求的有效期,单位为秒。有效期内,浏览器无需再次发送预检请求。
4.跨域和cookie
如果需要在跨域请求中携带 Cookie,服务器需要设置响应头"Access-Control-Allow-Credentials"为true
同时前端需要设置请求头"withCredentials"为true,否则无法携带 Cookie。
4.1 携带cookie时的限制
在跨域请求中携带Cookie时,浏览器会先发送OPTIONS预检请求,以检查是否允许跨域请求。
与不携带Cookie的情况相比,携带Cookie时"Access-Control-Allow-Origin"字段的限制更加严格:
-
字段不能为通配符*,否则浏览器会忽略"Access-Control-Allow-Credentials"字段的值,不会发送Cookie。
-
字段的值必须与请求头中"Origin"字段的值完全相同。