對幾種與跨域相關的請求頭做一個總結
關於跨域可以看:9 種常見的前端跨域解決方案(詳解)
看完后可以配合我的代碼做些實驗,看看注釋掉某個響應頭會發生什么,整體代碼會在最后貼出
1. 跨域簡單請求
需要在服務器響應頭中加 Access-Control-Allow-Origin
2. 跨域復雜請求
這時候會發送預檢請求options
,服務器需要在響應頭中添加Access-Control-Allow-Headers
來表明支持的請求頭
需要響應頭
Access-Control-Allow-Headers
Access-Control-Allow-Origin
響應頭中 Access-Control-Allow-Headers
的值應該設置為是使簡單請求變成非簡單請求的請求頭,有多個時則以逗號相連(當然,也可以設置為*)。在這里,因為發請求的時候我設置了
headers: {
"content-type": "application/json" //設置這個后,就不是簡單跨域請求了
},
所以 Access-Control-Allow-Headers 響應頭中至少要有 content-type
不加
Access-Control-Allow-Headers
則瀏覽器提示
Access to XMLHttpRequest at 'http://localhost:3333/test3' from origin 'http://localhost:2222' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
3. 跨域復雜請求,帶 cookie
需要響應頭
Access-Control-Allow-Headers
,並且不能為 *Access-Control-Allow-Origin
,並且不能為 *Access-Control-Allow-Credentials
為 true
4. 代碼
分了三個文件
4.1. test.html
在這里發送 ajax 請求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button type="button" id="test1">不跨域請求</button>
<button type="button" id="test2">跨域簡單請求</button>
<button type="button" id="test3">跨域復雜請求</button>
<button type="button" id="test4">跨域復雜請求,帶cookie</button>
<!-- <button type="button" id="test">測試</button> -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
var test1 = document.querySelector("#test1");
//不跨域請求
test1.addEventListener(
"click",
function() {
var url = `/test1`;
$.ajax({
url: url,
type: "get",
data: {
test: "test1"
},
success(res) {
var modal = `<div>不跨域請求成功:${res}</div>`;
$("body").append(modal); //htmlEscape()對字符進行轉義,js不會被執行,而是作為字符串
}
});
},
false
);
//跨域簡單請求
var test2 = document.querySelector("#test2");
test2.addEventListener(
"click",
function() {
var url = `http://localhost:3333/test2`;
$.ajax({
url: url,
type: "post",
data: {
test: "test2"
},
success(res) {
var modal = `<div>跨域簡單請求成功:${res}</div>`;
$("body").append(modal); //htmlEscape()對字符進行轉義,js不會被執行,而是作為字符串
}
});
},
false
);
// 跨域復雜請求
var test3 = document.querySelector("#test3");
test3.addEventListener(
"click",
function() {
var url = `http://localhost:3333/test3`;
$.ajax({
url: url,
type: "post",
headers: {
"content-type": "application/json" //設置這個后,就不是簡單跨域請求了
},
data: {
test: "test3"
},
success(res) {
var modal = `<div>跨域復雜請求成功:${res}</div>`;
$("body").append(modal); //htmlEscape()對字符進行轉義,js不會被執行,而是作為字符串
}
});
},
false
);
// 帶cookie的跨域請求
var test4 = document.querySelector("#test4");
test4.addEventListener(
"click",
function() {
var url = `http://localhost:3333/test4`;
$.ajax({
url: url,
type: "post",
headers: {
"content-type": "application/json" //設置這個后,就不是簡單跨域請求了
},
xhrFields: {
withCredentials: true // 前端設置是否帶cookie
},
data: {
test: "test4"
},
success(res) {
var modal = `<div>帶cookie的跨域請求成功:${res}</div>`;
$("body").append(modal); //htmlEscape()對字符進行轉義,js不會被執行,而是作為字符串
}
});
},
false
);
</script>
</body>
</html>
4.2. server.js
負責返回 test.html 和提供不跨域請求的接口
const fs = require("fs");
const http = require("http");
const qs = require("querystring");
const path = require("path");
http
.createServer((req, res) => {
let html = fs.readFileSync(path.resolve(__dirname, "./test.html"));
const url = req.url.split("?")[0];
const query = req.url.split("?")[1];
req.on("data", function(data1) {
postData += data1;
});
console.log("收到來自 ", url);
if (req.method == "GET") {
if (url == "/") {
//返回html模板
res.setHeader("set-cookie", "testCORS=riwang"); //設置cookie,后面發送帶cookie的請求時使用
res.end(html);
} else if (url == "/test1") {
//不跨域請求
res.end(query);
}
}
})
.listen(2222);
4.3. api.js
負責提供跨域請求的接口
/*
* @Author: riwang
* @Date: 2020-03-23 23:30:59
* @LastEditTime: 2020-03-24 00:49:29
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \RW 筆記\web安全\跨域\code\api.js
*/
const fs = require("fs");
const http = require("http");
const qs = require("querystring");
const path = require("path");
http
.createServer((req, res) => {
let html = fs.readFileSync(path.resolve(__dirname, "./test.html"));
const url = req.url.split("?")[0];
const query = req.url.split("?")[1];
const cookies = req.headers.cookie;
var postData = "";
req.on("data", function(data1) {
postData += data1;
});
console.log("收到來自 ", url);
if (req.method == "GET") {
res.end(html);
} else {
res.setHeader("set-cookie", "testCORS");
//跨域簡單請求
if (url == "/test2") {
res.setHeader("Access-Control-Allow-Origin", "*");
req.on("end", function() {
res.end(postData);
});
}
if (url == "/test3") {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "*");
req.on("end", function() {
res.end(postData);
});
}
if (url == "/test4") {
res.setHeader("Access-Control-Allow-Origin", req.headers.origin);
res.setHeader("Access-Control-Allow-Headers", "content-type"); //這里設置為*瀏覽器會報錯
res.setHeader("Access-Control-Allow-Credentials", true);
req.on("end", function() {
res.end(`postBody是${postData} |||||| cookies是${cookies}`);
});
}
}
})
.listen(3333);