关于CORS(跨域资源共享)的几个http请求头小实验
对几种与跨域相关的请求头做一个总结
关于跨域可以看: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);