HTML 跨域相关
本文的主要目的是简单介绍跨域问题以及相关的解决方案。
相关概念
跨域
跨域
,指的是浏览器不能通过JS进行不同域的数据传输或通讯。它是由浏览器的同源策略
造成的,是浏览器对Javascript施加的安全限制。
同源策略
同源策略
, 是指浏览器通过JS请求的数据的协议
、域
、端口
相同。
注意:
顶级域名和二级域名是不同域的,www.a.com 和 test.a.com 是不同域的
127.0.0.1 和 localhost 虽然都是指向本地,但是他们也是不同域的
举些例子:
不跨域:
URL | 说明 | 是否可以访问 |
---|---|---|
http://www.a.com/1.js http://www.a.com/2.js |
同一域名相同端口的不同文件 | 能访问 |
http://www.a.com/dir1/1.js http://www.a.com/dir2/2.js |
同一域名相同端口的不同目录不同文件 | 能访问 |
跨域:
URL | 说明 | 是否可以访问 |
---|---|---|
http://www.a.com/1.js https://www.a.com/2.js |
协议不同 | 不能访问 |
http://www.a.com/1.js http://www.b.com/2.js |
域不同 | 不能访问 |
http://www.a.com/1.js http://www.a.com:8080/2.js |
端口不同 | 不能访问 |
解决方案
解决跨域问题的方案有以下7种方案,其中包含三种常用方案和四中小技巧
常用方案:
- JSONP
- CORS
- 服务端代理
小技巧:
- location.hash
- window.name
- postMessage
- document.domain
1. JSONP
JSONP
,全称是JSON with padding
, 在Ajax中,用于解决老版本浏览器的跨域数据访问。
原理:
利用web浏览器加载js不受同源策略的影响,通过 script
标签进行跨域请求。
具体过程如下:
- 客户端设置好回调的函数,并将处理函数的函数名作为参数传递给服务器。
- 服务器接收到请求后,获取到回调函数的名称,并将处理后的数据放在回调函数的参数中,一起返回给客户端。
- 客户端接收到数据后,通过script标签,运行接收到的数据(调用本地处理函数)。
例子:
服务端:(Node 端口 3000)
|
|
客户端:(端口80)
|
|
优劣分析:
优点:
- 不受同源策略的影响,在老版本的浏览器上兼容性好。
- 无依赖,不需要其他( XMLHttpRequest 或 ActiveX )支持。
缺点:
- 只支持GET请求。
- 不能解决两个页面或iFrame之间的通信问题。
- 无法捕获 Jsonp 请求时的连接异常,只能通过超时进行处理
参考:
【原创】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例 - 随它去吧 - 博客园
2. CORS
CORS
,全称 跨域资源共享(Cross-origin resource sharing)
, 是W3C的一个新标准,他允许浏览器向跨源服务器,发出 XMLHttpRequest 请求。
CORS 需要浏览器和服务器同时支持才可以生效
|
|
其中 Access-Control-Allow-Origin
必须与客户端的 Origin
一致,否则将会跨域失效。*
表示接收来自任何域的请求。
优劣分析:
优点:
- 更加方便、安全
- 支持所有的HTTP请求类型
缺点:
- 是新的W3C标准,老浏览器不兼容(IE10 以上)
3. 服务端代理
跨域的请求通过后端代理,由后端代理代为请求,再将请求结果发送给客户端。
例子:Ngnix
|
|
webpack-dev 中的 proxyTable
|
|
4. location.hash
原理: 利用改变地址中的hash值不会导致页面刷新。通过改变hash值来传递数据,但是传递的数据量有限。
说明:
域1: 页面A、页面C(代理页)
域2: 页面B(数据接口所在的域)
具体流程:
页面A
通过js动态添加iframe
iframe
加载页面B
,页面B
获取组装数据。页面B
获取数据后,将数据作为页面C
的hash值,跳转到页面C
。页面C
再通过修改parent.location.hash
来将数据传递到页面A
|
|
|
|
缺点:
- 数据直接暴露在了 url 中
- 数据容量和类型都有限等等
5. window.name
window.name
是当前窗口的名字, iframe
通样有 window.name
属性。
window.name
在不同的页面(甚至不同域名)加载后依旧存在(如果没修改则值不会变化),并且可以支持非常长的 name 值(2MB)。
页面A
通过js动态添加iframe
iframe
加载页面B
, 并设置onload
函数,取到数据后跳转到页面C
,同时重新设置onload
函数读取数据。
|
|
|
|
6. postMessage
postMessage
HTML5 新增的一项功能,跨文档消息传输(Cross Document Messaging)
Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 都支持。
|
|
|
|
7. document.domain
这种方式用于主域相同而子域不同的情况下。通过设置 document.domain
来实现通讯。
|
|
|
|