获取无效 POST、PATCH 的 CORS 错误 - REST 端点
Posted
技术标签:
【中文标题】获取无效 POST、PATCH 的 CORS 错误 - REST 端点【英文标题】:Getting CORS Error for Invalid POST, PATCH - REST Endpoints 【发布时间】:2021-08-05 04:46:17 【问题描述】:我正在研究 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.
P.s.:- 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);
);
;
谢谢! 保持安全。
【问题讨论】:
您能否显示您的一个路由模块的完整代码,其中涉及不会导致此类错误的有效 POST 或 PATCH 端点? 感谢@IAmDranged。我添加了一个 adminRoutes POST 端点。如果我使用正确的端点请求它可以正常工作,即localhost:3000/admin/add/state 能否请您只显示您的 adminRoutes 模块的完整代码?只是想看看那里实际设置的所有路线。 我已经添加了adminRoutes和adminControllers的完整代码。如果您需要更多信息,请告诉我。谢谢你:) @IAmDranged 问题似乎出在 OPTIONS 上,它为无效的 POST/PATCH 端点提供 404。 【参考方案1】:对预检请求的响应未通过访问控制检查:它 没有 HTTP ok 状态。
此错误似乎表明 preflight request 失败,因为它的 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。
【讨论】:
这听起来很合理。我在某处读到 Express.js 默认处理 OPTIONS,即我们不需要定义 app.options(...);虽然我不确定。这个技巧看起来是处理这个问题的唯一方法。我发现了与您分享的内容相似的内容。if (req.method === "OPTIONS") res.sendStatus(200); else next();
我们可以将此行添加到我添加了 access-control-headers 的部分。 这仍然让我们想知道为什么有效和无效 POST/PATCH 请求之间存在这种偏颇性,而 GET 端点没有问题。
我刚刚进行了一次快速测试,实际上你似乎是正确的 express 做了一些隐式的 OPTIONS 路由处理。以上是关于获取无效 POST、PATCH 的 CORS 错误 - REST 端点的主要内容,如果未能解决你的问题,请参考以下文章
在 Django 中使用 Axios 和 CORS 获取 POST 请求的错误请求并做出反应
发送 post 请求时出现 CORS 错误,但在 Spring Boot 和 Reactjs 中未获取请求