閱讀目錄:
深入跨域問題(2) - 利用 CORS 解決跨域(本篇)
回答問題:
在閱讀這篇文章之前,讀讀第一篇文章,效果會更好!!!回答上一篇文章的問題:
- 不會觸發 預請求 ,因為是簡單的 GET 方法。
- 不會觸發 預請求,因為是簡單的 POST 方法,jquery 預設使用
application/x-www-form-urlencoded
。 - 會觸發 預請求 ,雖然是 POST 方法,但是
Content-Type
為application/json
。並非上文中的三種情況,text/plain
,multipart/form-data
,application/x-www-form-urlencoded
。
第三點,是最重要的一點,也是經常出錯的一點,記住觸發預請求三種情況 !!!
搭建跨域環境:
模擬客戶端請求:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Ajax測試</title>
</head>
<body>
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script>
$.ajax({
url: "http://localhost:3000",
type: "get",
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
</script>
</body>
</html>
複製程式碼
後文,將不再貼上 html
程式碼,jquery
也可以用 npm install jquery
下載。
模擬伺服器響應,新建 app.js 檔案,貼上並執行 :
const http = require('http');
const server = http.createServer((request, response) => {
if (request.url === '/') {
if (request.method === 'GET') {
response.end("{name: 'BruceLee', password: '123456'}");
}
if (request.method === 'POST') {
response.end("true");
}
}
response.end('false');
});
server.listen(3000, () => {
console.log('The server is running at http://localhost:3000');
});
複製程式碼
好了,現在雙擊開啟 html 檔案,就成了:
很明顯,這就是跨域報錯。
處理非預請求
在上述兩個例子中,我們說到,POST 和 GET 方法,都可以實現,非預請求。
關鍵程式碼:設定一條 響應首部欄位,允許 CORS 跨域資源共享:
response.writeHead(200, {
'Access-Control-Allow-Origin': '*
}
複製程式碼
這裡,我們設定為,所有客戶端都可以訪問。
完整程式碼:
const http = require('http');
const server = http.createServer((request, response) => {
if (request.url === '/') {
if (request.method === 'GET') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*' // 關鍵程式碼
});
response.end("{name: 'BruceLee', password: '123456'}");
}
if (request.method === 'POST') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*' // 關鍵程式碼
});
response.end("true");
}
}
response.end('false');
});
server.listen(3000, () => {
console.log('The server is running at http://localhost:3000');
});
複製程式碼
前端測試程式碼:
$.ajax({
url: "http://localhost:3000",
type: "get",
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
var data = { name: 'BruceLee', password: '123456' };
$.ajax({
url: "http://localhost:3000",
type: "post",
data: JSON.stringify(data),
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
複製程式碼
執行結果:
處理 非預請求 就是這麼簡單,只需要在後臺設定,一條 響應首部欄位 即可。
注意:我們使用 POST 方法時,Jquery 預設使用的 Content-Type: application/x-www-form-urlencoded
,所以不會觸發預請求 !!!
事實上,不僅僅是 Jquery ,axios 等封裝 Ajax 的庫,都預設採用 Content-Type: application/x-www-form-urlencoded
!!!
處理 POST 預請求
不僅僅是 POST ,所有 預請求 的處理方式都一樣。
POST 方法在設定 contentType
為 application/json
時會觸發預請求。
前端測試程式碼:
var data = { name: 'BruceLee', password: '123456' };
$.ajax({
url: "http://localhost:3000",
type: "post",
data: JSON.stringify(data),
contentType: 'application/json;charset=utf-8',
success: function (result) {
console.log(result);
},
error: function (msg) {
console.log(msg);
}
})
複製程式碼
注意,這裡的 contentType
已經修改為 application/json
,這種情況是會觸發 預請求 的 ! ! !
node 服務端程式碼:
const http = require('http');
const server = http.createServer((request, response) => {
if (request.url === '/') {
if (request.method === 'GET') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
response.end("{name: 'BruceLee', password: '123456'}");
}
if (request.method === 'POST') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
response.end( JSON.stringify({state: true}) );
}
if (request.method === 'OPTIONS') {
response.end( JSON.stringify({state: true}) );
}
}
response.end('false');
});
server.listen(3000, () => {
console.log('The server is running at http://localhost:3000');
});
複製程式碼
在這裡,我們增加了處理 OPTIONS 方法的邏輯。
測試結果:
很明顯,我們在 OPTIONS 方法內部沒有設定 CORS 響應首部欄位 ,所以出現跨域錯誤;
修改程式碼,關鍵程式碼:
if (request.method === 'OPTIONS') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*', // 設定 optins 方法允許所有伺服器訪問
'Access-Control-Allow-Methods': '*', // 允許訪問 POST PUT DELETE 等所有方法
});
response.end( JSON.stringify({state: true}) );
}
複製程式碼
在 node 程式碼中,我們增加對 OPTIONS 的處理,並且設定允許訪問, POST 方法。
修改程式碼後,重啟伺服器,並重新整理 html 頁面,結果為:
在這裡,仍然是有問題,按照報錯描述,我們應該設定 Access-Control-Allow-Headers
響應首部欄位 。
關鍵程式碼:
if (request.method === 'OPTIONS') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*', // 設定 optins 方法允許所有伺服器訪問
'Access-Control-Allow-Methods': '*', // 允許訪問路徑 '/' POST等所有方法
'Access-Control-Allow-Headers': 'Content-Type', // 允許類 Content-Type 頭部
});
response.end( JSON.stringify({state: true}) );
}
複製程式碼
我們需要設定,允許使用頭部為 Content-Type
的內容訪問。
完整程式碼:
const http = require('http');
const server = http.createServer((request, response) => {
if (request.url === '/') {
if (request.method === 'GET') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
response.end("{name: 'BruceLee', password: '123456'}");
}
if (request.method === 'POST') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*'
});
response.end( JSON.stringify({state: true}) );
}
if (request.method === 'OPTIONS') {
response.writeHead(200, {
'Access-Control-Allow-Origin': '*', // 設定 optins 方法允許所有伺服器訪問
'Access-Control-Allow-Methods': '*', // 允許訪問路徑 '/' POST等所有方法
'Access-Control-Allow-Headers': 'Content-Type', // 允許類 Content-Type 頭部
});
}
}
response.end('false');
});
server.listen(3000, () => {
console.log('The server is running at http://localhost:3000');
});
複製程式碼
執行結果:
-
預請求
-
POST 請求
這樣就完成,對 預請求 的處理。現在你可以狠狠地告訴後臺:是你沒有處理 OPTIONS 方法 !!!
好了,到這裡,知道了基礎的 預請求 處理的解決辦法了。
總結:
-
使用 CORS 跨域資源共享,是需要分成 預請求 與 非預請求 處理的。
-
非預請求,在伺服器內,只需要簡單設定:
'Access-Control-Allow-Origin': '* 複製程式碼
-
預請求,在伺服器內,至少要設定三個 響應首部欄位:
'Access-Control-Allow-Origin': ?, 'Access-Control-Allow-Methods': ?, 'Access-Control-Allow-Headers': 'Content-Type', 複製程式碼
-
前端使用
content-Type: application/json
的時候,必須注意這是 預請求 ,後端需要處理 OPTIONS 方法
參考與鳴謝:
- 跨域資源共享 CORS 詳解 阮一峰;
- 瀏覽器同源政策及其規避方法 阮一峰;
- HTTP訪問控制 (CORS) MDN 文件;
祝大家編碼愉快,喜歡的話點個贊再走唄!!!