javascript - 获取无效 POST、PATCH 的 CORS 错误 - REST 端点
问题描述
我正在研究 Express.js 并以 JSON 格式发送数据。在无效端点上传递 POST、PATCH 请求时出现 CORS 错误(如下)。对于有效的 POST、PATCH 端点,没有 CORS 错误。此外,对于无效/有效的 GET 端点请求,虽然没有 CORS 错误。
错误信息:
CORS 策略已阻止从源“https://www.google.com”获取“http://localhost:3000/invalid-endpoint”的访问权限:对预检请求的响应未通过访问控制检查:它没有 HTTP ok 状态。
我为无效的 POST 端点发送的获取命令:
fetch('http://localhost:3000/invalid-endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
someValue: "999",
})
}).then(response => {
return response.json()}).then(data => {
console.log(data)}).catch(err => {
console.log(err)});
我在我的应用程序中包含的标题:
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
完整代码:
//require modules.
//Headers
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
//Endpoint Routes
app.use("/state", stateRoutes);
app.use("/district", districtRoutes);
app.use('/admin', adminRoutes);
app.use("/", stateDistrictRoutes); //also Home
/* All the invalid endpoints should fall into this. But CORS Error preventing that for POST and PATCH. GET is working fine here. */
app.use((req, res, next) => {
const error = new Error("Invalid Endpoint.")
error.status = 404;
throw error;
});
//All the errors should fall into this at last.
app.use((error, req, res, next) => {
const status = error.status || 500;
const message = error.message;
res.status(status).json({
status: status,
message: message,
info: error.data || null,
});
});
//connection to database....etc.
Ps:- adminRoutes.js 页面(/admin)。下面的 POST/PATCH 请求可以完美运行。
const express = require("express");
const router = express.Router();
const adminControllers = require("../controllers/adminController");
const adminAuthControllers = require("../controllers/adminAuthController");
router.post("/add/state", adminControllers.postState);
router.post("/add/district", adminControllers.postDistrict);
router.patch("/update/state/:state", adminControllers.patchState);
router.patch("/update/:state/:district", adminControllers.patchDistrict);
router.post("/login", adminAuthControllers.postLogin);
router.post("/signup", adminAuthControllers.postSignup);
module.exports = router;
adminControllers 页面
const State = require("../models/state");
const District = require("../models/district");
exports.postState = (req, res, next) => {
const body = req.body;
State.findOne({ name: req.body.name })
.then((data) => {
if (data) {
const error = new Error("State already Exists!");
error.status = 409;
throw error;
}
const state = new State({
...body,
creator: {
lastUpdatedBy: req.userEmail,
createdBy: req.userEmail,
},
});
return state.save();
})
.then((response) => {
res.status(201).json({
message: "State created Successfully!",
data: response,
});
})
.catch((err) => {
if (!err.status) {
err.status = 500;
}
next(err);
});
};
exports.postDistrict = (req, res, next) => {
const body = req.body;
District.findOne({
name: req.body.name,
state: req.body.state,
})
.then((data) => {
if (data) {
const error = new Error("District already Exists!");
error.status = 409;
throw error;
}
const district = new District({
...body,
creator: {
lastUpdatedBy: req.userEmail,
createdBy: req.userEmail,
},
});
return district.save();
})
.then((response) => {
res.status(201).json({
message: "District created Successfully!",
data: response,
});
})
.catch((err) => {
if (!err.status) {
err.status = 500;
}
next(err);
});
};
exports.patchState = (req, res, next) => {
const state = req.params.state;
const body = req.body;
State.findOneAndUpdate(
{ name: state },
{ ...body },
{
new: true,
}
)
.then((response) => {
res.status(200).json({
message: "State updated Successfully!",
data: response,
});
})
.catch((err) => {
if (!err.status) {
err.status = 500;
}
next(err);
});
};
exports.patchDistrict = (req, res, next) => {
const state = req.params.state;
const district = req.params.district;
const body = req.body;
District.findOneAndUpdate(
{ name: district, state: state },
{ ...body },
{
new: true,
}
)
.then((response) => {
res.status(200).json({
message: "District updated Successfully!",
data: response,
});
})
.catch((err) => {
if (!err.status) {
err.status = 500;
}
next(err);
});
};
谢谢!注意安全。
解决方案
对预检请求的响应未通过访问控制检查:它没有 HTTP ok 状态。
此错误似乎表明预检请求失败,因为其 http 状态不在 200 范围内。请注意,此类预检请求仅适用于被认为复杂的 CORS 请求 - 例如 POST 或 PATCH 请求。
您的服务器没有设置为专门处理我可以看到的那些类型的预检请求 - 所以这些实际上最终被您的 404 路由处理程序捕获,因此您看到的错误消息。我不清楚的是为什么您的有效 POST 和 PATCH 端点不会以类似的方式出错。
为了避免此类错误,您应该将服务器设置为处理所有端点的预检请求 - 包括无效的请求。以下内容应该可以解决问题:
app.options("*", function(req, res) {
res.status(204).send()
)
请注意,这应该出现在你的包罗万象的 404 中间件之前 - 并且在 CORS 中间件之后。
编辑:根据下面的测试程序,实际上 express 会自动在中间件堆栈的末尾添加一个 OPTIONS 路由处理程序,用于路由处理程序已显式附加到的路径。
var express = require("express");
var logger = require('morgan');
var app = express()
app.use(logger('dev'));
app.get("/exist", function (req, res) {
res.send("ok")
})
app.options("/intercept", function (req, res) {
res.sendStatus(204)
})
app.listen(3000, () => console.log("Server listening"))
// console output
Server listening
OPTIONS /exist 200 2.972 ms - 8
OPTIONS /nonexistant 404 1.865 ms - 154
OPTIONS /intercept 204 0.597 ms - 11
作为旁注,express 似乎还添加了一个隐式 404 处理程序,尽管这可能不是您想要的 - 特别是内容类型是 html。
推荐阅读
- node.js - 动态命名空间 SocketIO - Django - NodeJS - Redis
- sequelize.js - 是否可以为续集模型定义默认排序顺序
- sql - 如何从 Oracle 中的表中获取信息?
- python-3.x - PDF转换为txt时设置阅读方向
- go - 有什么更好的方法来实现在社交网络中验证和执行帖子的例程?
- matlab - 在 'scatter' 调用中指定标记类型 * 和 * 大小
- sql - 从 APP 服务器而不是 WEB 服务器连接到 ASPState 数据库
- python - 如何删除以 Python 开头的行?
- sparklyr - 有没有办法在 Spark 本地模式下保存表并在重新连接后检索?
- python - Python 库 - __init__.py 不导入 .so 文件