获取无效 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 端点的主要内容,如果未能解决你的问题,请参考以下文章

在前端的 HTTP Post 调用上获取 CORS 错误

在 Django 中使用 Axios 和 CORS 获取 POST 请求的错误请求并做出反应

发送 post 请求时出现 CORS 错误,但在 Spring Boot 和 Reactjs 中未获取请求

已启用 CORS,但在 POST JSON 时,预检响应的 HTTP 状态代码 404 无效

弹簧CORS错误

Access-Control-Allow-Methods 不允许 CORS 方法 PATCH