本文總結自極客學院跨域Ajax實現視頻教程地址
常用的Ajax跨域請求有:CORS(跨域資源共享)、JSONP跨域和iframe跨域通信
一、CORS原理:
xhr level2支持的新標準,XMLHttpRequest隨想原生支持ajax,支持xhr level2的瀏覽器就能發起ajax跨域請求。但是它也有一定的安全限制,並不是支持了xhr level2的瀏覽器就能直接發起ajax跨域請求,只是說,它在標準上有實現跨域的功能,我們需要通過一定的安全策略,讓這個功能真正的支持起來。
二、CORS實現
- 實現CORS跨越請求關鍵在於,如何通過安全策略的設置,讓跨域ajax的功能真正的發起。
- 當瀏覽器判定一個請求爲跨域請求時,它會在請求頭信息中查找,是否存在一個“Access-Control-Allow-Origin”字段,並且該字段的值是允許一個域向另一個域發起請求的,這時請求就會被通過。
- 當我們向一個域發起請求時,後端實際上已經將結果相應給了前臺,但是前臺是否能夠使用後臺返回的數據,並交給前端腳本處理,取決於響應信息中是否有一個允許使用的標誌(Access-Control-Allow-Origin),它的值就是允許訪問的域(如:a.test.com)。如果我們希望一個域(a.test.com)能夠訪問另一個域(b.test.com),那麼另一個域(b.test.com)的響應信息中就必須包含允許訪問的標誌,它的值就是我們發起請求的域的名稱(a.test.com)
三、CORS跨域資源共享分類
- 簡單請求:瀏覽器直接發出CORS請求,具體來說,就是在頭信息中,增加一個Origin字段,用來說明本次請求來自哪個源(協議+域名+端口),服務器根據這個值,決定是否同意這次請求。
1.根據服務器的返回頭信息是否包含“Access-Control-Allow-Origin”字段,來判斷請求是否出錯(“Access-Control-Allow-Origin”字段是必須的,它的值要麼是Origin字段的值,要麼是一個星號“*”,表示接受任意域名的請求。)
2.CORS請求默認不發送Cookie和Http認證信息,如果要把Coolie發送到服務器,一方面要服務器同意,另一方面,開發者要在Ajax請求中打開“withCreditials”屬性:
var xhr = new XMLHttpRequest();
xhr.withCreditials = true;
- 非簡單請求:對服務器有特殊要求的請求,比如請求方式是 “PUT”或“DELETE”等。
非簡單請求的CORS請求會在正式通信前,增加一次HTTP查詢請求,成爲“預檢”請求(Preflight)。預檢請求用的請求方式是“OPTIONS”,表示該請求時用來詢問的,關鍵字段是Origin。
三、CORS跨域演示
修改host文件來模擬跨域(C:\Windows\System32\drivers\etc)
在host文件中添加:
127.0.0.1 a.test.com
127.0.0.1 b.test.com
便可利用a.test.com和b.test.com來模仿兩個域,實現跨域請求。
此處演示用node.js來作後臺處理。
- package.json文件
{
"name": "ajax-cross-domain",
"description": "cross ajaxs",
"version": "0.0.1",
"main": "./app.js",
"dependencies": {
"express": "4.x",
"body-parser": "*"
}
}
- app.js
var express = require('express');
var path = require('path');
var bodyParer = require('body-parser');
var app = express();
app.use(bodyParer.json());
app.use(bodyParer.urlencoded({
extended: false
}));
app.use(express.static(path.join(__dirname,'public')));
/*設置響應頭信息,在這裏做一個頭信息通用設置,即在發起請求前設置,達到在一個位置設置,所有位置都能生效的效果*/
app.use(function(req,res,next) {
res.header("Access-Control-Allow-Origin", "a.test.com");
//設置響應頭信息,若想讓所有請求域都通過,可以將值設置爲“*”
res.header("Access-Control-Allow-Headers", "test");
res.header("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
next();
});
app.use('/',require('./routes/index.js'));
var DEFAULT_PORT = 3000;
app.listen(DEFAULT_PORT);
console.log('server is listen at port: %d',DEFAULT_PORT);
- index.js
/**
* Created by lenovo on 2016/8/4.
*/
var express = require('express');
var router = express.Router();
router.all('/',function(req,res) {
res.sendFile('./public/index.html');
});
router.all('/test',function(req,res) {
res.send('ok');
});
module.exports = router;
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>cors</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/jquery-1.11.3.js"></script>
</head>
<body>
<div class="container">
<button class="btn btn-primary" onclick="crossAjax()">CORS</button>
</div>
<script>
function crossAjax() {
$.ajax('http://b.test.com:3000/test',{
type: 'PUT', //請求方式不是“get”時,需要在響應信息中設置“Access-Control-Allow-Methods”字段
headers: {test: 'ok'} //當設置了自定義頭部時,需要在響應信息中設置“Access-Control-Allow-Headers”字段,否則請求被阻止。
}).done(function(data) {
alert(data);
})
}
</script>
</body>
</html>
在瀏覽器中輸入a.test.com的域名,即可向b.test.com發送請求(反過來一樣可以。)