浏览器跨域问题解决办法
2017-05-26 10:37
246 查看
前言
之前在一个项目中,调用了别的部门的接口,但是由于存在跨域问题,只能进行简单的本地数据模拟调试,然后再把资源给对方进行联调。这样的方法肯定不是最佳方案,正好最近看到一篇文章,说到的就是跨域问题的解决办法,所以进行了学习和整理。同源政策
首先说说同源政策,最初,它的含义是指,A网页设置的Cookie,B网页不能打开,除非这两个网页“同源”。所谓“同源”,就是三个相同:协议相同
域名相同
端口相同
同源政策的目的就是为了防止信息泄露。
如果非同源,共有三种行为会受到限制:
Cookie、LocalStorage和IndexDB无法读取;
DOM无法获得;
Ajax请求不能发送。
下来说说如何针对上面三种情况进行跨域。
Cookie
Cookie是服务器写入浏览器的一小段信息,只有同源的网页才能共享,但是,两个页面一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain共享Cookie。举例来说,A网页是http://hr.163.com/a.html,
B网页是http://study.163.com/b.html。
主要设置相同的document.domain,两个网页就可以共享Cookie。
我们在两个页面都设置:
document.domain = '163.com';1
1
然后在a网页设置cookie:
document.cookie = "test1=hello";1
1
就可以在b网页读到这个cookie了:
var allCookie = document.cookie;1
1
我们也可以在服务器进行配置,指定Cookie的所属域名为一级域名,这样,二级三级域名不用做任何设置,都可以读取这个cookie:
Set-Cookie: key=value; domain=.163.com; path=/1
1
iframe
如果两个网页不同源,就无法拿到对方的DOM,典型的例子就是iframe窗口和window.open方法打开的窗口,它们与父窗口无法通信。父窗口获取子窗口:
document.getElementById("myIFrame").contentWindow.document1
1
子窗口获取父窗口:
window.parent.document.body1
1
如果两个窗口一级域名相同,只是二级域名不同,那么设置document.domain即可。
如果是完全不同源的网站,目前有三种方法,可以解决跨域窗口的通信问题。
片段标示符
window.name
跨文档通信API
片段标示符
片段标示符是URL的#后面的部分,比如http://163.com/a.html#fragment的#fragment,如果只是改变片段标示符,页面不会重新刷新。
父窗口可以把信息,写入子窗口的片段标示符:
var src = originURL + '#' + data; document.getElementById('myIFrame').src = src;1
2
1
2
子窗口可以通过监听hashchange事件得到通知:
window.onhashchange = checkMessage; function checkMessage() { var message = window.location.hash; // ... }1
2
3
4
5
6
1
2
3
4
5
6
同样的,子窗口也可以改变父窗口的片段标示符:
parent.location.href= target + "#" + hash;1
1
window.name
浏览器窗口有window.name属性,这个属性最大的特点是,无论是否同源,只要在同一个窗口里,前一个页面设置了这个属性,后一个网页可以读取它。父窗口先打开一个子窗口,载入一个不同源的页面,该网页将信息写入window.name属性:
window.name = data;1
1
子窗口跳回一个与主窗口同域的网址:
location = 'http://parent.url.com/xx.html';1
1
然后,主窗口就可以读取子窗口的window.name了:
var data = document.getElementById('myFrame').contentWindow.name;1
1
优点是window.name容量很大,可以放置非常长的字符串;缺点是必须监听子窗口window.name属性值的变化,影响页面性能。
window.postMessage
HTML5的全新API:跨文档通信API。父窗口
http://aaa.com
向子窗口http://bbb.com
发消息,调用postMessage方法就可以了:
var popup = window.open('http://bbb.com', 'title'); popup.postMessage('Hello World!', 'http://bbb.com');1
2
1
2
posetMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即”协议 + 域名 + 端口”。也
4000
可以设为*,表示不限制域名,向所有窗口发送。
子窗口向父窗口发送消息的写法类似:
window.opener.postMessage('Nice to see you', 'http://aaa.com');1
1
父窗口和子窗口都可以通过message事件,监听对方的消息:
window.addEventListener('message', function(e) { console.log(e.data); },false);1
2
3
1
2
3
message事件的事件对象event,提供以下三个属性:
event.source:发送信息的窗口
event.origin:信息发向的网址
event.data:信息内容
下面可以看看几个例子:
子窗口通过event.source属性引用父窗口,然后发送信息:
window.addEventListener('message', receiveMessage); function receiveMessage(event) { event.source.postMessage('Nice to see you!', '*'); }1
2
3
4
1
2
3
4
event.origin属性可以过滤不是发送本窗口的信息:
window.addEventListener('message', receiveMessage); function receiveMessage(event) { if (event.origin !== 'http://aaa.com') return; if (event.data === 'Hello World') { event.source.postMessage('Hello', event.origin); } else { console.log(event.data); } }1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
AJAX
ajax的跨域需求很常见的。现在有三种方法来解决:JSONP
WebSocket
CORS
JSONP
JSONP是服务器与客户端跨域通信的常用方法,最大的特点是简单适用,老式浏览器全部支持,服务器改造非常小。它的思想是,页面通过添加一个
<script>元素,向服务器请求JSON数据,服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
首先,网页动态插入
<script>元素,由它向跨源网址发出请求:
function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag('http://example.com/ip?callback=foo'); } function foo(data) { console.log('Your public IP address is: ' + data.ip); };1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14
服务器收到这个请求后,会将数据放在回调函数的参数位置返回:
foo({ "ip": "8.8.8.8" });1
2
3
1
2
3
JSONP**只能发GET请求**,这点需要注意。
WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨域通信。
下面举例子,浏览器发出的websocket请求头:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 Origin: http://example.com[/code]1 2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
其中Origin字段,表示该请求的请求源,服务器可以判断这个字段,判断是否允许本次通信,如果同意,做出反应:HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat1
2
3
4
5
6
1
2
3
4
5
6CORS
CORS可以允许任何类型的请求,是W3C的新标准。
首先,在请求头信息中添加Origin字段:GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...1
2
3
4
5
6
1
2
3
4
5
6
如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段:Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-81
2
3
4
5
1
2
3
4
5
如果不在允许范围内,也会返回正常的HTTP回应,但是**没有**Access-Control-Allow-Origin字段,浏览器发现后,就知道出错了,从而抛出错误,被XMLHttpRequest的onerror回调函数捕获。
根据详细的字段配置,可以看看这篇文章
,讲的非常详细。
相关文章推荐
- 浏览器跨域问题解决办法
- ajax 浏览器跨域问题的解决办法
- 记一次iphone 微信内置浏览器跨域无法获取cookie问题的解决方法
- 与seajs结合解决所有浏览器的跨域问题
- nodejs浏览器跨域问题解决
- 跨域问题解决办法
- 图片在IE8浏览器多一个有边框问题解决办法
- ExtJs关于grid高度自适应浏览器的问题解决办法
- CORS浏览器跨域以及node解决办法
- ExtJs关于grid高度自适应浏览器的问题解决办法
- “浏览器设置从上次停下的地方继续,但是电脑重启打开后还是主页”问题的解决办法
- div+css 浏览器兼容问题的解决办法
- iE浏览器和firefox浏览器中CSS兼容问题解决办法
- 解决跨域问题的几种办法
- 同源策略跨域问题及解决办法
- 浏览器的跨域问题及其解决方法
- web网站css,js更新后客户浏览器缓存问题,需要刷新才能正常展示的解决办法
- Flash实现Websocket的跨域问题-安全沙箱问题解决办法
- 解决浏览器跨域问题
- 浏览器跨域问题解决方案汇总