当访问一个资源文件时,如果从非该资源文件所在的服务器不同域名或者端口处进行访问时,该资源会发起一个跨域请求。
例如,网站A的地址是http://www.domain-a.com ,该网站中HTML页面通过 img
标签中的 src
属性请求http://www.domain-b.com/static/xxx.png 图片资源,此时,就发生了跨域请求。
处于安全考虑,浏览器限制从脚本内发起的跨域资源请求。例如,XHR和Fetch的API遵循同源策略。这意味着使用这些API只能从同一个域才能请求资源文件。
需要注意的是,跨域不一定是浏览器限制了发起跨域请求,也可能是跨域请求可以正常发起,但是返回的数据被浏览器截获。
最好的例子就是CSRF跨站攻击,有些浏览器不允许从HTTPS的网站跨域访问HTTP, 比如Chorme 和 Firefox,这些浏览器在请求还未发出时就会拦截请求。
CORS 机制允许Web 服务器对跨域访问进控制,从而保证跨域数据传输安全进行。目前浏览器都支持该机制,不过需要跨域访问需要客户端和服务端同时支持。
浏览器会针对XHR和Fetch中发起的跨域请求发送特殊的HTTP header 请求头信息。并且服务端也必须返回允许使用特定的跨域响应的header 头信息。
详细链接
drawImage
将image/video
画面绘制到canvasCORS标准新增了一组HTTP首部字段,允许服务器声明哪些请求源有权限访问哪些资源。另外,规范要求,那些可能导致服务器产生隐患的HTTP请求方法(除GET之外的请求),浏览器必须首先使用OPTIONS
方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务端返回允许响应后,才发起实际的HTTP请求。在预检请求的返回中,服务端也可以通知客户端,是否需要携带身份凭证(cookies和HTTP认证相关数据)。
这里,我们通过XHR对象介绍三个跨域资源共享的实例。
简单请求的特征:
Fetch 规范定义,不得自定义下面header之外的其他首部字段
Content-Type的值为下列之一
请求中任意XMLHttpRequestUpload
对象均没有注册任何事件监听器
ReadableStream
对象客户端和服务端之间使用CORS首部字段处理跨域权限:
查看一个跨域请求实例:
服务端返回的 Access-Control-Allow-Origin: *
表明该资源可以被任意域名访问,不收跨域限制。
预检请求要求必须首先使用OPTIONS
方法发起一个预检请求到服务端,来获知服务端是否允许该实际请求。
预检请求的满足条件:
XMLHttpRequestUpload
对象注册多个事件监听器ReadableStream
对象OPTIONS 请求
POST 请求
执行过程:
浏览器首先检查到,JS发起的请求需要被预检。Request Method:OPTIONS
表示这个是一个预检请求,该方法不会对服务器资源产生影响,预检请求中同时携带了下面两个首部字段:
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
首部字段Access-Control-Request-Method
通知服务端,实际请求将使用POST
方法。
首部字段Access-Control-Request-Headers
通知服务端,实际请求将携带Content-Type
字段。
服务端根据预检头信息,判断实际请求是否被允许。
通常情况下,浏览器发送跨域请求时不会发送身份凭证信息,如果要发送凭证信息的话,就要在对XHR对象设置特殊的标志位。
本例中,我们对XHR对象的withCredentials
标置设置为true,从而可以向跨域的服务器发送Cookies信息。
对于带凭证的请求,服务端不可将Access-Control-Allow-Origin
值设置为“*”。
这是因为请求的首部中携带Cookie信息,如果设置为“*”,请求将会失败。将Access-Control-Allow-Origin
值设置为请求方的host,则请求执行成功。
Origin
表明了首部字段预检请求或实际请求的源端。
Origin:
Access-Control-Request-Method
首部字段用于预检请求。作用是通知实际请求使用的HTTP方法。
Access-Control-Request-Method:<method>
Access-Control-Request-Headers
收不自动用于预检请求。做用户通知实际请求中携带的首部字段通知给服务端。
Access-Control-Request-Headers:
Access-Control-Allow-Origin: <origin> | *
orgin参数允许指定外域URI访问指定资源。对于不需要携带身份凭证的请求,服务端可以指定该字符为通配符,它允许来自所有域的访问。
如果,允许接收指定一个具体的域请求时
Access-Control-Allow-Origin: http://google.com
服务端指定的时一个具体的域而不是“*”,那么响应的首部中Vary
字段值必须包含 Origin 。这将告诉客户端:服务器对不同源站返回不同的内容。
服务端将浏览器允许访问的头放入白名单,例如:
Access-Control-Expose-Headers: x-header
这样,浏览器就可以根据服务端的响应头白名单进行访问。
指明该预检请求可以被缓存多久。
当浏览器的credentials
设置为true时,是否允许浏览器读取response内容。
Access-Control-Allow-Credentials: true
指明浏览器实际允许使用的HTTP方法。
Access-Control-Allow-Methods: <methods>
指明浏览器实际允许携带的首部字段。
Access-Control-Allow-Headers: <filed-name>