在开发过程中经常会涉及跨域问题,解决跨域问题的方案也有很多种,接下来就来梳理一下前端跨域的常用方法。
同源策略
何为跨域,跨域是相对于同源而言。协议、域名和端口均相同,则为同源。
浏览器通过同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制,摘抄自MDN。
常见解决方案
document.domain
这种方案主要用于主域相同,子域不同的跨域情况。例如: https://jdc.jd.com/
和 https://www.jd.com/
。
通过在https://www.jd.com/打开一个https://jdc.jd.com/,此时JDC的域名是jdc.jd.com/
,通过控制台执行document.domain = 'jd.com'
;。强制设置主域,实现同源。
1 | var jdc = window.open('https://jdc.jd.com/'); |
通常的做法是通过iframe
加载一个跨域页面资源。因为window.open
这个方法在浏览器中会被当做谈广告禁止掉。
1 | <iframe id="sub" src="http://sub.domain.com/index.html"></iframe> |
1 | <script> |
location.hash
这种跨域方法主要是通过设置/监听url的hash部分,来实现跨域,同时需要借助第三个页面来进行辅助。
上图就是三个页面的包含关系,以及hash
的传递过程。
1 | <iframe id="iframe-b" src="http://domain-b.com/b.html"></iframe> |
1 | <iframe id="iframe-c" src="http://domain-a.com/c.html"></iframe> |
1 | <script> |
由于a页面和c页面是同域资源,所以c页面可以通过window.parent.parent
访问a页面资源。
window.name
这个方案类似location.hash
,需要通过第三个页面进行辅助。window.name
属性是用来获取/设置窗口的名称。需要注意的是,当前窗口的window.name
并不会因为页面的重载和跳转而更改,所以可以利用这个特性将跨域的window.name
通过重定向到同域页面进行读取。
1 | <script> |
1 | <scirpt> |
同域c页面,可以是一个空页面,不需要进行任何操作。
JSONP
JSONP(JSON with Padding)是JSON的一种使用方式。这种方式允许用户传递一个callback
参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据。
众所周知,html页面中所有带有src
属性的标签(<img>
,<script>
和iframe
)都拥有跨域能力。所以最简单的实现方式就是动态加载JS。
客户端
1 | function todo(data){ |
服务端
1 | /* 服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。 */ |
todo()
函数会被作为全局函数来执行,只要定义了todo()
函数,该函数就会被立即调用。
postMessage
window.postMessage
是HTML5中一个安全的,基于事件的消息API。
1 | otherWindow.postMessage(message, targetOrigin, [transfer]); |
postMessage()
,方法包含三个参数:
message
: 消息内容targetOrigin
: 接受消息窗口的源,即”协议 + 域名 + 端口”。也可以设置为通配符*
,向所有窗口发送transfer
: 可选参数(布尔值),是一串和message 同时传递的Transferable
对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
发送者和接收者都可以通过message
事件,监听对方的消息。message
事件的事件对象event
包含三个属性:
event.source
: 发送消息的窗口对象的引用,可以用此在两个窗口建立双向通信。event.origin
: 发送消息的URIevent.data
: 消息内容
1 | <script> |
1 | <script> |
WebSocket
WebSocket
是一种HTML5的一种新的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案,详细介绍请访问MDN。
1 | /* websocket协议为ws/wss, 类似http/https的区别 */ |
WebSocket
的优势是除了可以实现跨域,还有就是可以保持长连接,而不需要通过轮询实现实时性。
CORS
CORS
是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
只需要后端同学支持就ok,前端不需要做很多额外工作(除了携带cookie
)。
只要服务器返回的相应中包含头部信息Access-Control-Allow-Origin: domain-name
,domain-name
为允许跨域的域名,也可以设置成*
,浏览器就会允许本次跨域请求。
结语
以上就是我所了解的跨域的解决方案,希望对你有所帮助。