1.什麼是跨域?
通過XHR實現Ajax通信的一個主要限制,來源於跨域安全策略,默認情況下,XHR對象只能訪問與包含它的頁面位於同一個域中的資源,這種安全策略可以預防某些惡意行爲。
2.什麼是CORS?
CORS(Cross-Origin Resource Sharing) -- 跨域資源共享,W3C的工作草案,定義了在必須訪問跨域資源時,瀏覽器與服務器該如何進行溝通,CORS背後的基本思想就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從而決定請求或者相應是成功還是失敗。
正文:
在某些條件下,請求後臺需要在headers中添加Token用以鑑權,這個時候需要CORS來幫忙,這裏使用Node.js的Express來模擬後臺配置響應頭,使得將Token放入headers變爲可行:
首先新建文件夾,並安裝express:
npm install express
然後新建入口index.js、測試請求index.html
index.js:
const express = require('express');
const app = express()
app.listen(3300,()=>console.log('啓動服務'));
app.post('/post',(req,res)=>{
let resObj = {
msg:"CORS",
headers:req.headers
}
res.json(resObj )
})
簡單啓動了一個端口爲3300的服務,定義post請求一半公開側事故
index.html:
//引用於JavaScript高級程序設計的兼容性xhr寫法
function createXHR() {
if (typeof XMLHttpRequest != 'undefined') {
return new XMLHttpRequest();
} else if (typeof ActiveXObject != 'undefined') {
if (typeof arguments.callee.activeXString != 'string') {
var versions = [
'MSXML2 .XMLHttp.6.0', 'MSXML2.XMLHttp.3.0',
'MSXML2.XMLHttp'
],
i, len;
for (i = 0, len = versions.length; i < len; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex) {
// pass;
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error('no XHR Object')
}
}
}
//簡單封裝ajax 傳入url,headers,data
function ajax(url, headers, data) {
return new Promise((resolve, reject) => {
var xhr = createXHR();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.readyState >= 200 && xhr.status < 300) || xhr.status == 304) {
resolve(xhr.responseText);
} else {
reject(xhr.status)
console.log('Request was unsuccessful: ' + xhr.status)
}
}
};
xhr.open('post', url, true);
if (headers) {
headers.forEach(element => {
let {
name,
value
} = element;
xhr.setRequestHeader(name, value);
});
}
xhr.send(data)
})
}
//測試用 隨便寫的
var data = new FormData();
data.append('name', 'Nicholas');
let url = 'http://127.0.0.1:3300/post'
// 設置頭 將Token帶入
let headers = [
{
name: "Token",
value: "XXX3RT-AASDR-FFDSX-RRESA"
}
]
//調用
ajax(url, headers, data).then(res => {
console.log(res)
}).catch(e => {
console.log(e)
})
這裏簡單寫了一個Ajax並將token放入headers,這個時候如果向測試口發請求:
首先會報跨域錯誤:未設置Access-Control-Allow-Origin頭,現在在index.js中把頭加上:
const express = require('express');
const app = express()
app.listen(3300,()=>console.log('啓動服務'));
//express中間件
app.use("*",(req,res,next)=>{
// 允許任意源
res.header('Access-Control-Allow-Origin',"*");
next();
})
app.post('/post',(req,res)=>{
let resObj = {
msg:"CORS",
headers:req.headers
}
res.json(resObj )
})
這個時候再請求:
會出現另一個跨域錯誤:不允許我們更改請求頭,這是因爲:
跨域的XHR存在一些限制:
- 不能使用setRequestHeader()設置自定義頭部
- 不能發送和接收cookie
- 調用getAllResponseHeaders()方法總會返回空字符串
3.Preflighted Requests
CORS通過這個透明服務驗證機制支持開發人員用自定義頭部、GET,POST以外的方法,以及不同類型的主體內容,在使用這些類項來發送請求時,就會向服務器發送一個Preflight請求,這種請求使用OPTIONS方法。
這就需要我們在index.js中通過響應與瀏覽器進行溝通:
const express = require('express');
const app = express()
app.listen(3300,()=>console.log('啓動服務'));
// 中間件
app.use("*",(req,res,next)=>{
// 允許任意源
res.header('Access-Control-Allow-Origin',"*");
// 允許的請求方法 修改請求頭時會發送預檢請求
res.header('Access-Control-Allow-Methods','GET,POST,OPTIONS')
// 允許自定義頭部
res.header('Access-Control-Allow-Headers',"Token");
// 收到遇見請求返回成功狀態
if(req.method == 'OPTIONS'){
res.send(200)
}else{
next();
}
})
app.post('/post',(req,res)=>{
let resObj = {
msg:"CORS",
headers:req.headers
}
res.json(resObj )
})
將這些響應設置好以後我們再請求,首先看一下netWork:
發現發送了兩次請求:
第一次爲OPTIONS:
第二次爲真正的POST請求:
請求成功,並且Token帶入了headers,至此完成了模擬CORS頭部帶Token請求的寫法.
注:如果在index.js的中間件中增加:
res.header('Access-Control-Max-Age',1728000)
Preflight請求結束以後,結果將按照響應中指定的時間緩存起來,再次請求將不會在進行Preflight請求。
參考:JavaScript高級程序設計,https://www.jianshu.com/p/f650dfad5574