什么是跨域?前端
同源:协议、域名、端口相同。不一样源便是跨域。两个不一样的域名即便指向同一个IP地址,也不一样源。nginx
同源策略限制的内容有哪些?json
DOM 层面:限制了不一样源 JavaScript 对当前 DOM 对象的读写操做;canvas
数据层面:限制了不一样源站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据;segmentfault
网络层面:限制了经过 XMLHttpRequest 等方式将站点的数据发送给不一样源的站点。跨域
容许跨域的三个标签浏览器
<img>
、<link>
、<script>
服务器
跨域的解决方案有哪些?网络
(1) 同源策略限制下请求接口的方式:app
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
的值为*
,若是设置了会致使请求失败。参考: