-
什么是跨域?
同源:协议、域名、端口相同。不同源即是跨域。两个不同的域名即使指向同一个IP地址,也不同源。
-
同源策略限制的内容有哪些?
DOM 层面:限制了不同源 JavaScript 对当前 DOM 对象的读写操作;
数据层面:限制了不同源站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据;
网络层面:限制了通过 XMLHttpRequest 等方式将站点的数据发送给不同源的站点。
-
允许跨域的三个标签
<img>、<link>、<script> -
跨域的解决方案有哪些?
(1) 同源策略限制下请求接口的方式:
-
JSONP- 首先是利用
<script>标签的src属性来实现跨域。 - 通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后返回,实现服务器端向客户端通信。
- 由于使用
<script>标签的src属性,因此只支持 get 方法。
- 首先是利用
-
空
iframe加form- 创建一个
iframe元素和form元素; - 如果需要在响应返回时执行一些操作,可以在
iframe的load事件处理程序中添加相应代码; - 指定
form元素的action属性为请求的url,method属性为post,target属性为iframe的name,最后调用form的submit()方法发送请求。
- 创建一个
-
CORS分为简单请求和应当先发送预检请求的请求。简单请求设置
Origin头部,服务器返回响应数据时设置Access-Control-Allow-Origin头部。非简单请求先发送预检请求,预检请求完成后再发送实际请求。 -
代理
使用
nginx代理配置 server_name 为请求发起方的域名,然后设置location拦截前端的跨域请求,再将请求代理到服务器域名即可绕过浏览器的同源策略。 -
WebSocket
(2) 同源限制下Dom查询的方式
-
postMessage使用 HTML5 提供的
postMessage()方法可以实现不同页面的跨域通讯。在页面中使用postMessage()发送消息,使用addEventListener()监听回复的消息。 -
document.domain适用于主域名相同,子域名不同的
iframe跨域。给两个页面指定document.domain = 主域名即可访问对方的window对象了。 -
canvas操作图片的跨域问题跨域的图片只要能在网页中正常显示,就可以使用
canvas的drawImage()方法绘制出来。但是如果要对图片进行getImageData()或toDataURL()操作,则需要处理跨域问题。- 响应头中设置
Access-Control-Allow-Origin头部,允许请求发送方访问 - 创建了
Image实例后,设置实例的crossOrigin属性值为''(crossOrigin的属性值不为use-credentials时,全部都会解析为anonymous,表示不需要携带任何非匿名信息给服务器)
- 响应头中设置
-
-
什么是 CORS ?
CORS 即跨域资源共享标准,它新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,对可能对服务器数据产生副作用的 HTTP 请求方法,浏览器必须先使用
OPTIONS方法发起一个预检请求,从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证。 -
CORS 的三个访问控制场景
(1) 简单请求满足以下所有条件:
-
使用的请求方法为
GET、HEAD、POST中的一种; -
首部字段仅限于
Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width和Width所组成的集合中的元素; -
Content-Type值为text/plain、multipart/form-data、application/x-www-form-urlencoded中的一个; -
请求中的任意
XMLHttpRequestUpload对象都没有注册任何事件监听器; -
请求中没有使用
ReadableStream对象。简单请求中头部字段
Origin值为自己的域名,响应头部携带字段Access-Control-Allow-Origin,值为包含请求域名的值或*,这样即可完成跨域请求。
(2) 应当先发送预检请求的请求满足下述任一条件:
- 使用的请求方法为
PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH中的一种; - 首部字段设置了
Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width之外的字段; Content-Type值不属于application/x-www-form-urlencoded、multipart/form-data、text-plain之一;- 请求中的
XMLHttpRequestUpload对象注册了任意多个事件监听器; - 请求中使用了
ReadableStream对象。
发送一个使用
OPTIONS方法的预检请求,用以从服务器获取更多信息。预检请求完成之后,发送实际请求。// 预检请求头部,这些头部无须手动设置,使用XMLHttpRequest对象发起跨域请求时,它们已经被设置就绪 Origin: 请求来源 Access-Control-Request-Method: 实际请求将使用的方法 Access-Control-Request-Headers: 实际请求将使用的自定义首部字段 // 预检请求响应头部 Access-Control-Allow-Origin: 允许访问的域名 Access-Control-Allow-Methods: 允许使用的请求方法 Access-Control-Allow-Headers: 允许使用的自定义首部 Access-Control-Max-Age: 响应的有效时间。在有效时间内,浏览器无须为同一请求再次发起预检请求(3) 附带身份凭证的请求
- 跨域请求需要发送凭证信息时,
XMLHttpRequest请求需要将withCredentials标识设置为true,Fetch请求需要将credentials: 'include'添加到fetch()方法的init对象中。响应头部中需要携带Access-Control-Allow-Credentials: true头部,否则浏览器不会把响应内容返回给请求发送者。 - 附带凭证的请求,服务器不可以设置
Access-Control-Allow-Origin的值为*,如果设置了会导致请求失败。
-
参考:
- 【segmentfault】不要再问我跨域的问题了:segmentfault.com/a/119000001…
- 解决canvas图片getImageData, toDataURL跨域问题:www.zhangxinxu.com/wordpress/2…
- 【MDN】HTTP访问控制(CORS):developer.mozilla.org/zh-CN/docs/…