首页 > 解决方案 > 获取无效 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);
    });
};

谢谢!注意安全。

标签: javascriptrestexpresscors

解决方案


对预检请求的响应未通过访问控制检查:它没有 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。


推荐阅读