一.CORS
1.CORS需要瀏覽器和服務(wù)器同時(shí)支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低于IE10。
整個(gè)CORS通信過(guò)程,都是瀏覽器自動(dòng)完成,不需要用戶參與。對(duì)于開發(fā)者來(lái)說(shuō),CORS通信與同源的AJAX通信沒(méi)有差別,代碼完全一樣。瀏覽器一旦發(fā)現(xiàn)AJAX請(qǐng)求跨源,就會(huì)自動(dòng)添加一些附加的頭信息,有時(shí)還會(huì)多出一次附加的請(qǐng)求,但用戶不會(huì)有感覺。
因此,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信。
2.兩種請(qǐng)求方式
瀏覽器將CORS請(qǐng)求分成兩類:簡(jiǎn)單請(qǐng)求(simple request)和非簡(jiǎn)單請(qǐng)求(not-so-simple request)。
只要同時(shí)滿足以下兩大條件,就屬于簡(jiǎn)單請(qǐng)求。
(1) 請(qǐng)求方法是以下三種方法之一:
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時(shí)滿足上面兩個(gè)條件,就屬于非簡(jiǎn)單請(qǐng)求。
瀏覽器對(duì)這兩種請(qǐng)求的處理,是不一樣的。
3基本流程
- 簡(jiǎn)單請(qǐng)求: 正常發(fā)送Ajax請(qǐng)求=>瀏覽器檢測(cè)到此請(qǐng)求為跨域請(qǐng)求自動(dòng)增加一個(gè)origin字段=>服務(wù)器根據(jù)這個(gè)值決定是否同意這次請(qǐng)求=>瀏覽器得到回應(yīng),根據(jù)返回的頭信息沒(méi)有包含Access-Control-Allow-Origin字段判斷本次CORS請(qǐng)求是否成功
GET /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Host: api.alice.com
Accept-Language: en-USConnection: keep-alive
User-Agent: Mozilla/5.0...
上面的頭信息中,Origin字段用來(lái)說(shuō)明,本次請(qǐng)求來(lái)自哪個(gè)源(協(xié)議 + 域名 + 端口)。服務(wù)器根據(jù)這個(gè)值,決定是否同意這次請(qǐng)求。
- 非簡(jiǎn)單請(qǐng)求:非簡(jiǎn)單請(qǐng)求是那種對(duì)服務(wù)器有特殊要求的請(qǐng)求,比如請(qǐng)求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡(jiǎn)單請(qǐng)求的CORS請(qǐng)求,會(huì)在正式通信之前,增加一次HTTP查詢請(qǐng)求,稱為"預(yù)檢"請(qǐng)求(preflight)。
OPTIONS /cors HTTP/1.1
Origin: [http://api.bob.com](http://api.bob.com/)
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
瀏覽器發(fā)出預(yù)檢請(qǐng)求=> 服務(wù)器回應(yīng)預(yù)檢請(qǐng)求==> 服務(wù)器同意則會(huì)返回一個(gè)帶Access-Control-Allow-Origin頭信息的HTTP回應(yīng)=> 瀏覽器判斷預(yù)檢請(qǐng)求是否被允許 =>如果預(yù)檢請(qǐng)求被通過(guò),以后每次的非簡(jiǎn)單請(qǐng)求,就都和簡(jiǎn)單請(qǐng)求一樣
參考文章
二.JSONP
JSONP的實(shí)現(xiàn)思路
1.前端創(chuàng)建script標(biāo)記,設(shè)置src,添加到head中(可以往body中添加)
2.后臺(tái)返回一個(gè)js變量jsonp,這個(gè)jsonp就是請(qǐng)求后的JSON數(shù)據(jù)
3.回調(diào)完成后刪除script標(biāo)記(還有一些清理工作如避免部分瀏覽器內(nèi)存泄露等)
范例:
//服務(wù)器代碼
var http = require('http');
var urllib = require('url');
var port = 10011;
var data = {'name': 'jifeng', 'company': 'taobao'};
http.createServer(function(req, res){
var params = urllib.parse(req.url, true);
console.log(params);
if (params.query && params.query.callback) {
//console.log(params.query.callback);
var str = params.query.callback + '(' + JSON.stringify(data) + ')';//jsonp
res.end(str);
} else {
res.end(JSON.stringify(data));//普通的json
}
}).listen(port, function(){
console.log('server is listening on port ' + port);
})
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<script type="text/javascript">
function get_jsonp() {
$.getJSON("http://10.232.36.110:10011?callback=?", //瀏覽器端代碼,jQuery實(shí)現(xiàn)
function(data) {
$('#result').val('My name is: ' + data.name);
});
}
</script>
<a href="javascript:get_jsonp();">Click me</a><br />
<textarea id="result" cols="50" rows="3"></textarea>
</body>
</html>
三.postmanage
HTML5中最酷的新功能之一就是 跨文檔消息傳輸Cross Document Messaging。下一代瀏覽器都將支持這個(gè)功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已經(jīng)使用了這個(gè)功能,用postMessage支持基于web的實(shí)時(shí)消息傳遞。
otherWindow.postMessage(message, targetOrigin);
otherWindow: 對(duì)接收信息頁(yè)面的window的引用??梢允琼?yè)面中iframe的contentWindow屬性;window.open的返回值;通過(guò)name或下標(biāo)從window.frames取到的值。
message: 所要發(fā)送的數(shù)據(jù),string類型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制
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'就不會(huì)執(zhí)行postMessage了
ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>
b.com/index.html中的代碼:
<script type="text/javascript">
window.addEventListener('message', function(event){
// 通過(guò)origin屬性判斷消息來(lái)源地址
if (event.origin == 'http://a.com') {
alert(event.data); // 彈出"I was there!"
alert(event.source); // 對(duì)a.com、index.html中window對(duì)象的引用
// 但由于同源策略,這里event.source不可以訪問(wèn)window對(duì)象
}
}, false);
</script>