测试demo
简单请求
不会触发 CORS 预检请求。这样的请求为 简单请求,。若请求满足所有下述条件,则该请求可视为 简单请求:
- HTTP 方法限制:只能使用 GET、HEAD、POST 这三种 HTTP 方法之一。如果请求使用了其他 HTTP 方法,就不再被视为简单请求。
- 自定义标头限制:请求的 HTTP 标头只能是以下几种常见的标头:
Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(仅限于application/x-www-form-urlencoded、multipart/form-data、text/plain)。HTML 头部 header field 字段:DPR、Download、Save-Data、Viewport-Width、WIdth。如果请求使用了其他标头,同样不再被视为简单请求。 - 请求中没有使用 ReadableStream 对象。
- 不使用自定义请求标头:请求不能包含用户自定义的标头。
- 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
服务器端:
const express = require("express");
const app = express();
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Allow-Credentials", true);
if (req.method === "OPTIONS") {
res.sendStatus(200);
} else {
next();
}
});
// 当前端发起请求时返回认证信息
app.get("/api/user", (req, res) => {
// res.setHeader("Access-Control-Allow-Origin", "http://22.4.48.239:5500");
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
// res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
// res.setHeader("Access-Control-Allow-Credentials", true);
const user = { name: "Alice" };
res.json(user);
});
// 处理 POST 请求
app.post("/api/data", (req, res) => {
const data = req.body;
// 处理数据
res.json({ message: "Data received!" });
});
app.listen(3000, () => {
console.log("Server started on port 3000");
});
前端测试页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./axios.js"></script>
</head>
<body>
<script>
document.cookie = "name=value; expires=Thu, 01 Jan 2099 00:00:00 UTC; ";
// fetch 测试
// setTimeout(() => {
// fetch("http://22.4.48.239:3000/api/user", { credentials: 'include' })
// .then((response) => response.json())
// .then((data) => console.log(data))
// .catch((error) => console.error(error));
// }, 1000);
// axios 测试
axios
.get("http://22.4.48.239:3000/api/user", { withCredentials: true })
.then(function (response) {
console.log(response);
});
</script>
</body>
</html>
- 携带认证cookie时, 是携带当前域的cookie, 不是服务接口域的
- 携带不携带仅从chrome调试器很难看出, 可以从调试器的network面板里, 看服务详情信息的headers面板里的General里有无 Remote Address: xx.xx 信息, 有的就不携带认证. 也可看有无cookie头. 可以从调试器用 copy as fetch可以看出 (这种方式也要看浏览器心情, 测试偶尔可以, 偶尔带不带认证拷出来的fetch请求信息一样的), 见下图:
拷出来的代码如下:
fetch("http://22.4.48.239:3000/api/user", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,de;q=0.6,zh-TW;q=0.5,fr;q=0.4,ko;q=0.3",
"cache-control": "no-cache",
"pragma": "no-cache"
},
"referrer": "http://22.4.48.239:5500/",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": null,
"method": "GET",
"mode": "cors",
"credentials": "include" // include 代表要携带, omit 代表不携带
});
"credentials" 字段值: include 代表要携带, omit 代表不携带
- 要携带认证, Access-Control-Allow-Origin 必须为请求的域名才可以. 不携带设置为 * 或 请求的域名都可以.
- get请求可以成功, 但post请求不可以. 要检查是否是对"OPTIONS"请求进行了处理.
//node.js
if(req.method==="OPTIONS"){
res.sendStatus(200)
}else{
next()
}
如果有nginx在前面, 要修改配置:
if ($request_method = 'OPTIONS'){
return 200;
}
- 类似下面的报错, 说header field 不被允许, 要在 Access-Control-Allow-Headers 设置里添加对应的字段.
Acess to fetch at 'https://xxxx' from origin 'https://yyyyyyyy' has been blocked by CORS policy: Request header field theme is not allowed by Access-Control-Allow-Headers in preflight response.
-
避免使用含有自定义头部信息的请求:由于浏览器默认不会将某些自定义的头部信息包含在 OPTIONS 请求中,因此如果使用了这些头部信息,则浏览器会自动发送 OPTIONS 请求来预检。因此,如果不需要使用自定义头部信息,则可以避免这种情况发生。
-
增加 POST 请求的缓存时间:如果已经完成了一次预检,可以设置 POST 请求的缓存时间来避免浏览器重复发送 OPTIONS 请求。在响应头中,可以设置
Access-Control-Max-Age属性来指定缓存时间(单位为秒)。