Open WarpPrism opened 7 years ago
浏览器的安全基石是“同源政策”,所谓同源是指协议相同,域名相同,端口相同,只要其中有一个不同,则称为不同源。不同源的网站之间不能够相互请求数据,以确保用户数据的安全性。 但有的时候,一个网站不得不请求别的域上面的数据,这个过程就称为跨域。
跨域的实现方法有以下几种:
JSONP(JSON with padding)的原理是script标签不受同源安全策略限制,它可以向别的域发送get请求。
function handleResponse(data) { console.log('The response data is:' + data); } //动态添加script标签 var script = document.createElement('script'); script.src = 'http://www.baidu.com/json?callback=handleResponse'; script.setAttribute('type', 'text/javascript'); document.body.appendChild(script);
后台收到get请求后,根据callback参数生成相应的JSONP数据 handleResponse({'data': serverdata}),这段数据返回前端就会被当作js代码执行,触发回调函数。
$(document).ready(function(){ $.ajax({ type: 'get', async: false, // 查询CA1998次航班的信息 url: 'http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998', dataType: 'jsonp', //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonp: 'callback', //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据 jsonpCallback: 'flightHandler', success: (json) => { alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。'); }, error: () => { alert('fail'); } }); });
CORS是一个W3C标准,全称为跨域资源共享(cross-origin resource sharing),它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
整个CORS通信过程都由浏览器自动完成,用户不需要参与,对于前端开发者来说,同源ajax和CORS的代码完全相同,因此,实现CORS的关键在于服务器是否提供CORS接口。
简单请求例子:
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...
若服务器允许来自http://api.bob.com的跨域请求,则会进行如下响应:
Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true //是否允许发送cookie Access-Control-Expose-Headers: FooBar // 额外的header字段 Content-Type: text/html; charset=utf-8
若不允许,则不会设置Access-Control-Allow-Origin字段,如果服务器将此字段设为*,则表示服务器接受所有域的跨域请求。
Access-Control-Allow-Credentials: true 则表明服务器接受cookie,同时开发者应在AJAX打开withCredentials属性,以允许浏览器发送cookie:
var xhr = new XMLHttpRequest(); xhr.withCredentials = true;
跨域资源共享 CORS 详解
即不同window间通过HTML5的API postMessage进行跨域通信,其格式为:
otherWindow.postMessage(data, targetOrigin); // otherWindow指要接收消息的窗口,targetOrigin限制接收窗口所在的域,若不想限制,设为*即可
示例:
<!--a.com/index.html--> <iframe id="ifr" src="b.com/index.html"></iframe> <script type="text/javascript"> window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = 'http://b.com'; // 若写成'http://b.com/c/proxy.html'效果一样 // 若写成'http://c.com'就不会执行postMessage了 ifr.contentWindow.postMessage('Message from a.com!', targetOrigin); }; </script>
<!--b.com/index.html--> <script type="text/javascript"> window.addEventListener('message', function(event){ // 通过origin属性判断消息来源地址 if (event.origin == 'http://a.com') { alert(event.data); // 弹出"Message from a.com!" alert(event.source); // 对a.com、index.html中window对象的引用 // 但由于同源策略,这里event.source不可以访问window对象 } }, false); </script>
原理: windoe.name 的值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)
a.com/1.html
<script type="text/javascript"> function getData() { var ifr = document.getElementById('proxy'); ifr.src = 'a.com/2.html'; //跳转到同源网站 ifr.onLoad = function() { var data = ifr.contentWindow.name; alert(data); } } </script> <iframe src='http://other-origin/data.html' style='display:none' onLoad='getData()'></iframe>
other-origin/data.html
var data = { name: 'xiaoming', age: 12 }; window.name = JSON.stringify(data);
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
请求头信息:(多了个 origin) 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 响应头:(如果origin在白名单内) HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
跨域问题
浏览器的安全基石是“同源政策”,所谓同源是指协议相同,域名相同,端口相同,只要其中有一个不同,则称为不同源。不同源的网站之间不能够相互请求数据,以确保用户数据的安全性。 但有的时候,一个网站不得不请求别的域上面的数据,这个过程就称为跨域。
跨域的实现方法有以下几种:
(1)JSONP
JSONP(JSON with padding)的原理是script标签不受同源安全策略限制,它可以向别的域发送get请求。
后台收到get请求后,根据callback参数生成相应的JSONP数据 handleResponse({'data': serverdata}),这段数据返回前端就会被当作js代码执行,触发回调函数。
jQuery和JSONP
(2)CORS
CORS是一个W3C标准,全称为跨域资源共享(cross-origin resource sharing),它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
整个CORS通信过程都由浏览器自动完成,用户不需要参与,对于前端开发者来说,同源ajax和CORS的代码完全相同,因此,实现CORS的关键在于服务器是否提供CORS接口。
简单请求例子:
若服务器允许来自http://api.bob.com的跨域请求,则会进行如下响应:
若不允许,则不会设置Access-Control-Allow-Origin字段,如果服务器将此字段设为*,则表示服务器接受所有域的跨域请求。
Access-Control-Allow-Credentials: true 则表明服务器接受cookie,同时开发者应在AJAX打开withCredentials属性,以允许浏览器发送cookie:
跨域资源共享 CORS 详解
(3)iframe + HTML5 postMessage
即不同window间通过HTML5的API postMessage进行跨域通信,其格式为:
示例:
(4)iframe + window.name
原理: windoe.name 的值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)
a.com/1.html
other-origin/data.html
(5)WebSocket
WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。