Post 请求 Node.js 和 React 的 CORS 错误

Posted

技术标签:

【中文标题】Post 请求 Node.js 和 React 的 CORS 错误【英文标题】:CORS error for Post requests Node.js and React 【发布时间】:2021-11-02 11:17:29 【问题描述】:

我对代码的 get 请求有效,但是当涉及到 post 请求时,我收到一个 cors 错误:

CORS 策略已阻止从源“client.com”访问“api.com”处的 XMLHttpRequest:请求的资源上不存在“Access-Control-Allow-Origin”标头。

我已经尝试了所有与解决此问题相关的方法,但我一直得到相同的结果。我想知道是不是因为我的套接字服务器?很郁闷。

我的节点代码:

const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const session = require("cookie-session");
const cors = require("cors");
const server = require("http").createServer(app);
const rateLimit = require("express-rate-limit");
const io = require("socket.io")(server, 
  cors: 
    origin: "*",
  ,
);
const multer = require('multer');
const  v4: uuidv4  = require('uuid');
let path = require('path');


app.use(bodyParser.urlencoded( extended: true ));
app.use(bodyParser.json());

app.use(
  session(
    resave: false,
    saveUninitialized: true,
    secret: "shhhhhh",
  )
);

app.use(function (req, res, next) 
  res.header("Access-Control-Allow-Origin", "*");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept"
  );
  next();
);



app.use(cors());

const 
  registerTeacher,
  loginTeacher,
  getOneTeacher,
  getAllTeachers,
  postAvailibility,
  deleteExpired
 = require("./teachers");

const 
  loginStudent,
  registerStudent,
  getOneStudent,
  bookTeacher,
 = require("./students");

const  postMessage, getMessages  = require("./classes");

///images
const storage = multer.diskStorage(
  destination: function(req, file, cb) 
      cb(null, 'images');
  ,
  filename: function(req, file, cb)    
      cb(null, uuidv4() + '-' + Date.now() + path.extname(file.originalname));
  
);

const fileFilter = (req, file, cb) => 
  const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
  if(allowedFileTypes.includes(file.mimetype)) 
      cb(null, true);
   else 
      cb(null, false);
  


let upload = multer( storage, fileFilter );

////teacher routes
app.post("/api/teachers/register", upload.single('photo'), registerTeacher);
app.post("/api/teachers/login", loginTeacher);
app.get("/api/teachers/:teacherId", getOneTeacher);
app.post("/api/teachers/:teacherId/calender", postAvailibility);
app.delete("/api/teachers/:teacherId/calender", deleteExpired)

///student routes
app.post("/api/students/register", upload.single('photo'), registerStudent);
app.post("/api/students/login", loginStudent);
app.get("/api/students/:studentId", getOneStudent);
app.get("/api/students/:studentId/ourteachers", getAllTeachers);
app.post("/api/students/:studentId/ourteachers/:teacherId", bookTeacher);


///Class Routes for getting messages only
app.put("/api/:classId/:studentId/:teacherId", postMessage);
app.get("/api/:classId/:studentId/:teacherId", getMessages);

////socket
let users = [];

const addUser = (userId, socketId) => 
  !users.some((user) => user.userId === userId) &&
    users.push( userId, socketId );
;

const removeUser = (socketId) => 
  users = users.filter((user) => user.socketId !== socketId);
;

const getUser = (userId) => 
  return users.find((user) => user.userId === userId);
;

io.on("connection", (socket) => 
  ///connected
  ///take userId and socketId
  socket.on("addUser", (userId) => 
    addUser(userId, socket.id);
    io.emit("getUsers", users);
  );

  ///send and get message
  socket.on("sendMessage", ( senderId, receiverId, text ) => 
    const user = getUser(receiverId);
    io.to(user.socketId).emit("getMessage", 
      senderId,
      text,
    );
  );

  socket.emit("me", socket.id);

  socket.on("callUser", (data) => 
    io.to(data.userToCall).emit("callUser", 
      signal: data.signalData,
      from: data.from,
      name: data.name,
    );
  );

  socket.on("answerCall", (data) => 
    io.to(data.to).emit("callAccepted", data.signal);
  );

  ///for mouse

  socket.on("sendLines", (data) => 
    io.to(data.to).emit("getLines", data.lines);
  );

  socket.on("clearLines", (data) => 
    io.to(data.to).emit("getClearLines", data.lines);
  );

  ///for slides

  socket.on('sendSlidePosition', (data)=>
    io.to(data.to).emit('getSlidePosition', data.slidePosition)
  )

  socket.on('sendAllow', (data)=>
    io.to(data.to).emit('getAllow', data.data)
  )

  ///disconnected
  socket.on("disconnect", () => 
    console.log("User disconnected");
    removeUser(socket.id);
    io.emit("getUsers", users);
  );
);

let port = process.env.PORT;
if (port == null || port == "") 
  port = 5000;


server.listen(port, function () 
  console.log("Successful port connection");
);

我的反应代码:

import  useState  from "react";
import axios from "axios";
import  useHistory  from "react-router-dom";
import  FormControl, Input, Button  from "@material-ui/core";

function TeacherSignup() 
  let history = useHistory();

  const url =
    "myapi.com";
  const [data, setData] = useState(
    name: "",
    email: "",
    age: "",
    phoneNumber: "",
    nationality: "",
    country: "",
    city: "",
    street: "",
    postalCode: "",
    password: "",
    confirmPassword: "",
  );

  function submit(e) 
    e.preventDefault();
    if (data.password !== data.confirmPassword) 
      alert("passwords must match");
    
    axios
      .post(url, 
        name: data.name,
        email: data.email,
        age: data.age,
        phoneNumber: data.phoneNumber,
        country: data.country,
        city: data.city,
        street: data.street,
        password: data.password,
        postalCode: data.postalCode,
        nationality: data.nationality,
      )
      .then((res) => 
        console.log(res.data._id);
        history.push(`/teachers/$res.data._id`);
      );
  

  function handle(e) 
    const newData =  ...data ;
    newData[e.target.id] = e.target.value;
    setData(newData);
    console.log(newData);
  

  return (
    <div className='login-form'>
      <h1>Register Teacher</h1>
      <form onSubmit=(e) => submit(e)>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="name"
              value=data.name
              placeholder="Name"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="email"
              value=data.email
              placeholder="Email"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="age"
              value=data.age
              placeholder="Age"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="phoneNumber"
              value=data.phoneNumber
              placeholder="Phone Number"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="nationality"
              value=data.nationality
              placeholder="Nationality"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="country"
              value=data.country
              placeholder="Country"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="city"
              value=data.city
              placeholder="City"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="street"
              value=data.street
              placeholder="Street"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="postalCode"
              value=data.postalCode
              placeholder="Postal Code"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="password"
              value=data.password
              placeholder="Password"
              type="text"
            ></Input>
          </FormControl>
        </div>
        <div className="login-input">
          <FormControl>
            <Input
              onChange=(e) => handle(e)
              id="confirmPassword"
              value=data.confirmPassword
              placeholder="Confirm Password"
              type="text"
            ></Input>
          </FormControl>
        </div>

        <Button type="submit">Submit</Button>
      </form>
    </div>
  );


export default TeacherSignup;

【问题讨论】:

为什么要在 app.use(cors()) 调用之前明确设置 CORS 响应标头?我会尝试删除它,因为它可能与 cors 冲突。 我不想挑剔,但错误是提到 api.com 并且您的反应服务器正在连接到 myapi.com 这只是一个错字还是这两个不同的服务器? 您可以尝试删除app.use(cors()) 并在您的自定义cors 处理程序(即res.header.set("Access-Control-Allow-Origin", "*"))中设置一个断点以查看该断点是否被命中?如果它被命中,则检查该特定请求的响应是否包含 ACAO 标头。如果不是(如错误所示),还有其他东西会干扰您的响应并可能重置标题... 如果断点未命中,则说明您的服务器设置存在其他问题,无法执行所有中间件。然后你应该尝试将你的服务器减少到一个最小的例子。例如尝试删除socket.io 和其他中间件并检查问题是否仍然存在......如果你有工作配置,添加回各个部分,看看问题是否再次出现...... 你能不能也检查一下浏览器,如果有预检(OPTIONS)请求被发送,如果是,这个请求的结果是什么... 【参考方案1】:

我将删除在 app.use(cors()) 之前设置的显式 CORS 标头,并将 methods: ['GET', 'POST', 'DELETE', 'OPTIONS'] 添加到您的 io 配置中。

从 Socket.IO v3 开始,您需要显式启用跨域资源共享 (CORS)。

【讨论】:

我试过了,还是不行。同样的错误 很难说没有关于确切错误消息的更多信息。确保支持预检请求:app.options('*', cors()). 您可能还试图传递您的cors 配置不接受的凭据或自定义标头。你能指出确切的错误吗?

以上是关于Post 请求 Node.js 和 React 的 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

Node.js:POST - 请求方法:OPTIONS 状态代码:403 Forbidden

如何在 node.js 中处理 POST 请求

Node.js使用Express实现Get和Post请求

Node.js POST API 和请求正文的解析

node.js之路由,中间件,ge请求和post请求的参数

Node.js GET/POST请求