前言
CORS对于前端开发而言,应该是一个非常重要的问题,不过对于大部分项目来说都是前后端同源,因此也就不会涉及到CORS的问题,即便是面试时大部分人也只是知道个大概,没有人去深究其中的细节实现。
直到前不久,我在开发过程中遇到了这方面的问题之后才查阅了一些资料,并详细地对CORS的机制进行了了解。因此这篇文也是给有类似经历的前端开发者写的,主要着重于实践中遇到的问题。文章后附有前后端代码可供参考。
什么是CORS
在讲CORS之前我们需要了解一下浏览器加载资源的机制:
- 同源策略,同源即两个 URL 的
protocol、port (en-US) (如果有指定的话)和 host 都相同
的话,则这两个URL是同源。同源策略是一个重要的安全策略,它能够限制资源间的交互,帮助阻隔恶意文档,减少可能被攻击的媒介。 - 和同源策略相对的则是跨源,也就是我们常说的跨域,只要
protocol、port和 host 有一个不同
则为跨域。
下表给出了与 URL store.company.com/dir/page.ht… 的源进行对比:
URL | 结果 | 原因 | store.company.com/dir2/other.… | 同源 | 只有路径不同 | store.company.com/dir/inner/a… | 同源 | 只有路径不同 | store.company.com/secure.html | 跨源 | 协议不同 | store.company.com:81/dir/etc.htm… | 跨源 | 端口不同 ( http:// 默认端口是80) | news.company.com/dir/other.h… | 跨源 | 主机不同 |
---|
同源策略这里不多讲了,对于大部分的项目前后端同源的话一般不会有什么问题。但当前后端分离部署产生跨域问题时,由于出于安全考虑浏览器是会限制跨域请求的,这时我们就可以采用CORS
来解决问题。
CORS即Cross-Origin Resource Sharing
,中文译作跨域资源共享。CORS机制允许服务器通过标识除自己以外的域来允许浏览器访问这些跨域资源,也是我们处理跨域问题中常用的一种解决方式。
(我相信大部分人在面试的时候对于跨域的解决方法都能张嘴就来,但实际操作的时候还真不一定就能非常熟练,所以还是实践出真知)
简单请求与预检请求
在CORS规范中,讲请求分为两种,即简单请求和预检请求。
简单请求定义如下:
- 使用方法为
GET
、HEAD
、POST
之一 - 允许人为设定的头部字段(即对CORS安全的首部字段)
- Accept
- Accept-Language
- Content-Language
- Content-Type (有额外限制)
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
- 请求中的任意
XMLHttpRequestUpload
对象均没有注册任何事件监听器;XMLHttpRequestUpload
对象可以使用XMLHttpRequest.upload
属性访问 - 请求中没有使用
ReadableStream
对象
其中Content-Type
的值仅限以下三者之一:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
满足以上条件的请求即为简单请求。
而不满足以上条件的请求则会触发预检请求。浏览器必须首先使用OPTIONS
方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。"预检请求“可以避免跨域请求对服务器产生未预期的影响。
下图为一个预检请求的示例:
该请求为从localhost:8080
发出到localhost:3000
的一个GET请求,由于端口不同而产生了跨域请求。但是因为请求头header
中携带了一个自定义的字段X-Custom-Header
,因此触发了预检请求,预检请求通过后才进行GET请求。
携带Cookie的请求
CORS可以基于HTTP cookies
和HTTP认证信息发送身份凭证。一般对于跨域请求浏览器不会发送身份凭证信息。想要发送凭证信息需要进行相应的设置:
客户端中的请求进行如下设置后方能向服务端发送带有Cookie的请求:
withCredentials: true
服务端则需要对响应头设置:
Access-Control-Allow-Credentials: true
如果服务端未进行设置,则浏览器将不会把响应内容返回。
要注意的是,对于需要携带Cookie的请求,服务器不得设置Access-Control-Allow-Origin
的值为*
,这种情况下请求会失败,如下图:
CORS设置
下面就介绍一下常用的CORS设置。
HTTP响应头字段
Access-Control-Allow-Origin
该字段指定了允许访问该资源的外域URI:
Access-Control-Allow-Origin: http://localhost:8080
上述设置允许来自http://localhost:8080 的请求访问该资源。也可以设置为通配符*
表示允许所有域的请求访问资源。对于需要携带Cookie的请求服务器可以指定值为通配符。
Access-Control-Expose-Headers
在跨源访问时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到一些最基本的响应头。默认情况下只有以下七种响应头可以暴露给外部:
Cache-Control
Content-Language
Content-Type
Content-Length
Expires
Last-Modified
Pragma
如果要访问其他头,则需要服务器设置本响应头。
Access-Control-Expose-Headers: X-Kuma-Revision, X-Custom-Header
上述设置将两个自定义的响应头暴露给浏览器。我们看下下图所示的例子:
服务端自定义了一个X-Expose-Headers的响应头,但没有设置Access-Control-Expose-Headers
,因此即使在浏览器打印响应对象,headers中也是拿不到的。
Access-Control-Max-Age
用于指定预检请求的结果能够被缓存多久。
Access-Control-Max-Age: 3600
上述设置表示预检请求的结果将在3600秒内是有效的。
Access-Control-Allow-Credentials
用于指定当浏览器的credentials
设置为true
时是否允许浏览器读取response
的内容。当用在对预检请求的响应中时,它指定了实际的请求是否可以使用credentials
,详见上一节。
Access-Control-Allow-Methods
用于预检请求的响应。指明了实际请求所允许使用的 HTTP 方法。
Access-Control-Allow-Methods: PUT, GET, POST, DELETE
上述设置表示该请求允许使用PUT、GET、POST、DELETE方法调用。
Access-Control-Allow-Headers
用于预检请求的响应。其指明了实际请求中允许携带的首部字段。
Access-Control-Allow-Headers: token, originalUrl
以上设置表示实际请求中允许携带名为token和originalUrl的首部字段。
HTTP请求头字段
下面列出了可用于发起跨域请求的首部字段,这些字段不需要开发者手动设置。
Origin
Origin字段表明预检请求或实际请求的源站。
Access-Control-Request-Method
用于预检请求,作用是将实际请求所使用的 HTTP 方法告诉服务器。
Access-Control-Request-Headers
用于预检请求。作用是将实际请求所携带的首部字段告诉服务器。
DEMO源码
github.com/Yayoiqz/cor… 上述的CORS设置DEMO中都有,可以调试。
参考
- 跨源资源共享(CORS)
- 深入理解 CORS
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!