CORS(Cross-origin resource sharing) 中文名称"跨域资源共享",由于安全原因,Web 应用程序默认情况只能在同源(协议、域名和端口)的情况下向服务器获取数据。
主要有以下三种行为会受到限制:
Cookie、LocalStorage 和 IndexDB 无法读取。 DOM 无法获得。禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。 AJAX 请求不能发送(XMLHttpRequest)。
但是在日常的业务开发中,我们是需要经常访问跨域资源的。CORS 机制允许 Web 应用进行跨源访问,需要浏览器和服务器同时支持。整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
CORS 将请求分成了两类:简单请求(Simple Request)和非简单请求。其中非简单请求会触发预检请求(Preflight Request)。满足以下两大条件的请求就属于简单请求。
请求方法为下列方法之一 GET HEAD POST 请求的 HTTP 的头部信息不超出以下几种字段 Accept Accept-Language Content-Language Content-Type -> { text/plain, multipart/form-data, application/x-www-form-urlencoded }undefinedDPR Downlink Save-Data Viewport-Width Width
这是为了兼容表单(form),因为历史上表单一直可以发出跨域请求。
凡是不满足上面两个条件,就属于非简单请求。例如 COS V5 版本的 XML 接口中,当 Content-Type 为 application/xml 时就会触发 CORS 预检请求。
对于简单请求,浏览器直接发出 CORS 请求。具体来说,就是在头信息之中,增加一个 Origin 字段。下面我们先看一下 COS 服务器端对于跨域访问 CORS 设置中的各参数的配置作用,并给出结果图。
浏览器在发起跨域请求时会自动向 HTTP Header 添加一个额外的请求头字段:Origin。Origin 字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。
另外还有三个 Sec-Fetch-*
开头的字段,这是一个新的草案 Fetch Metadata Request Headers。
Sec-Fetch-Mode
代表请求的模式,主要有 cors、navigate、nested-navigate、no-cors 等等。
Sec-Fetch-Site
代表请求的来源是同源还是跨域。
作用:COS 服务端允许跨域的源。
如果 Origin 指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。浏览器发现,这个回应的头信息没有包含 Access-Control-Allow-Origin
字段,就知道出错了,从而抛出一个错误,被 XMLHttpRequest 的 onerror 回调函数捕获。
作用:HTTP 请求方法的限制
这个参数应该还是比较容易理解的,允许浏览器的 CORS 请求会用到哪些 HTTP 方法。
作用:允许浏览器端能够获取相应的 header 值
CORS 请求时,如果服务器端没有设置对应的Access-Control-Expose-Headers
字段,浏览器通过请求响应后的 Header 如下,比如我们非常熟悉的 x-cos-request-id
、ETag
等头部无法在浏览器中无法获取到。
在 COS CORS 设置中把Expose-Headers
置为*
再来看一下结果
就可以拿到 COS 服务器端返回的全部 Header 字段了
作用:是否允许发送 Cookie
这个头部在 COS CORS 设置中并没有对应的选项,如果要发送 Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。当 Access-Control-Allow-Origin
指定源后,COS 服务器端会自动设置该字段为 true。
当然,如果需要使用该特性,开发者也必须在请求时打开withCredentials
属性。
预检请求是在发送实际请求前,客户端先发送一次 OPTIONS
方法请求到服务器端来确认请求是否通过,可以避免跨域请求对服务器的用户数据造成影响。
如何判断是否会发送预检请求可以参考第一部分的请求分类。
预检请求用的请求方法是 OPTIONS
,表示这个请求是用来询问的。
当然也需要带上 Origin
字段。
除了 Origin 字段,预检请求的头信息还包括两个特殊字段 Access-Control-Request-Method
和 Access-Control-Request-Headers
。
该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法。如 PUT、POST、GET 等。
该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段。
如上图在请求的时候加上了自定义头部 X-Custom-Header = shuoweiwu
,所以触发了预检请求。
Provisional headers are shown
字面意思是"显示了临时报文头",代表请求被阻塞,未收到响应,说明 请求并没有发出去。
看下控制台报错和 Network 里的请求详情,是由于预检请求报错 403,被浏览器拦截了。
Access to XMLHttpRequest at 'https://xxxxxxxxx-xxxxxxxxxx.cos.ap-guangzhou.myqcloud.com/test/3.jpg' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Access-Control-Allow-Origin
和 Access-Control-Allow-Methods
同简单请求一样,分别用于判定请求源和请求方法,需要注意的是以下两个配置项。
作用:表示服务器允许请求中携带的请求头部字段。
比如上面预检请求中的 X-Custom-Header
头部。
作用:指定本次预检请求的有效期,单位为秒。
如果设置 超时 Max-Age
为 0,则浏览器发送请求的时候始终都会先发送 OPTIONS 预检请求。
COS 中的 CORS 配置:
预检请求:
实际请求:
超时 Max-Age
设置为 600 时,只有在第一次请求时发送了 OPTIONS 预检请求。
当跨域请求被重定向时,中间服务器返回的 CORS 相关的响应头应当与最终服务器保持一致。 任何一级的 CORS 失败都会导致 CORS 失败。即需要满足每一级的 CORS 都能够通过验证。
浏览器会直接访问重定向后的地址,可以跟随多次重定向。但是需要注意的一点就是:
重定向后请求头 Origin 字段会被设为 null
重定向请求:
重定向后 Origin 字段被置为 null,导致重定向后的跨域请求失败:
解决方法有以下两种:
Access-Control-Allow-Origin
字段为 *
Access-Control-Allow-Origin
字段为 null
具有 src 属性的 HTML 标签都可以跨域
<link>,<script>,<img>
等标签是可以直接进行跨域访问的,但是不会产生跨域头。
当然这里最常见的问题就是已经配置好了跨域头,用 curl 测试生效,但是在前端页面访问的时候没有生效,看 Network 的请求头里确实是没有 CORS 的相关字段。
由于img
标签是可以直接进行跨域访问的,在请求 COS 前,img
标签加载了同样的图片,因为img
加载在前,等到访问 COS 中的资源的时候,浏览器直接使用了缓存,缓存中是没有跨域头的,导致了跨域失败。
如何判定有可能是命中了浏览器缓存?
Provisional headers are shown
字段,如上所述,代表请求没有发出来,有可能是命中了浏览器缓存。使用场景以及命中浏览器缓存后的解决方案:
Cache-Control
头部关闭缓存。如在 COS 上传的时候加上该头部Cache-Control:no-cache
,或者复制该资源的时候加上该头部。如果对象数量不是很多,可以直接在COS控制台点开该对象详情,设置自定义Headers。<img>
标签的 crossorigin 属性的值为 anonymous,强制图片每次请求都使用 XHR 的 CORS 请求。Cache-Control
头部关闭缓存,并且刷新对应的CDN的URL。<img>
标签的 crossorigin 属性的值为 anonymous,强制图片每次请求都使用 XHR 的 CORS 请求。ps: 其中设置 <img>
标签的 crossorigin 属性的方式是可以使用本地缓存的,但是可能有些浏览器是不支持 crossOrigin 的。
Vary头部 -> COS对跨域的进一步支持
Vary头部的使用场景是本地浏览器通过多个域名访问同一个URL,带上Vary头部后浏览器会缓存住不同Origin的请求,这个头部COS侧会尽快安排上,丰富产品的特性。
其他常见问题:
ETag
等字段 -> 参考上面 CORS 的 Expose Header 的配置Reference:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。