由于 CORS,无法在 Express 和 React 应用程序之间获取

Posted

技术标签:

【中文标题】由于 CORS,无法在 Express 和 React 应用程序之间获取【英文标题】:Cannot fetch between Express and React apps due to CORS 【发布时间】:2020-01-09 11:34:03 【问题描述】:

我的应用运行良好,并且能够在我的 Express 和 React 服务器之间获取数据。我重新组织了我的代码,现在我无法摆脱 CORS 错误并且根本无法获取任何数据。我无法继续我的项目,我自己也想不通,我真的试过了。

前端工作正常,直到我尝试登录,然后身份验证失败

我已尝试添加标头并已将 CORS 安装到我的 express 应用中。我在我的 react package.json 中指定了一个代理到 express URL。

这是我的 Express server.js
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const cors = require('cors');
const methodOverride = require('method-override');

const db = require('./db/index.js')
db.on('error', console.error.bind(console, 'MongoDB connection error:'))

require('dotenv').config();
const app = express();

app.disable('x-powered-by');

app.use(function(req, res, next) 
  // Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');

// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);

// Pass to next layer of middleware
next();
);

app.use(methodOverride('_method'));
app.use(bodyParser.urlencoded( extended: true ));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(cors(
  origin: 'http://localhost:8080'
));

app.use(express.static(path.join(__dirname, '../build')));

app.get('/', function (req, res) 
  res.sendFile(path.join(__dirname, '../build', 'index.html'));
);


const userRouter = require('./routes/user-routes')
app.use('/api', userRouter)

const fileRouter = require('./routes/file-routes')
app.use('/file', fileRouter)

// mongoose.connection.once('open', run);

app.listen(process.env.PORT || 8080);
console.log('Server is listening on port ' + process.env.PORT);
这是我的用户控制器
const User = require('../models/Users');
const secretShh = 'mysecretsshhh';
const jwt = require('jsonwebtoken');

const home = (req, res) =>  
    res.send('Welcome!');
;

const secret = (req, res) => 
    res.send('The password is potato');
;

const register = (req, res) => 
    const  email, password  = req.body;
    const user = new User( email, password );
    user.save(function(err) 
      if (err) 
        console.log(err);
        res.status(500).send("Error registering new user please try again.");
       else 
        res.status(200).send("Welcome to the club!");
      
    );
  ;

const authenticate = (req, res) => 
    const  email, password  = req.body;
    User.findOne( email , function(err, user) 
      if (err) 
        console.error(err);
        res.status(500)
          .json(
          error: 'Internal error please try again'
        );
       else if (!user) 
        res.status(401)
          .json(
          error: 'Incorrect email or password'
        );
       else 
        user.isCorrectPassword(password, function(err, same) 
          if (err) 
            res.status(500)
              .json(
              error: 'Internal error please try again'
            );
           else if (!same) 
            res.status(401)
              .json(
              error: 'Incorrect email or password'
            );
           else 
            // Issue token
            const payload =  email ;
            const token = jwt.sign(payload, secretShh, 
              expiresIn: '1h'
            );
            res.cookie('token', token,  httpOnly: true ).sendStatus(200);
          
        );
      
    );
;

const token = (req, res) => 
    res.sendStatus(200);
;

module.exports = 
    home,
    secret,
    register,
    authenticate,
    token

这是我的用户路线
const express = require('express')

const UserCtrl = require('../controllers/user-ctrl')
const withAuth = require('../middleware');

const router = express.Router()

router.get('/home', UserCtrl.home)
router.get('/secret', withAuth, UserCtrl.secret)
router.post('/register', UserCtrl.register)
router.post('/authenticate', UserCtrl.authenticate)
router.get('/checktoken', withAuth, UserCtrl.token)

module.exports = router
这是一个检查令牌的中间件函数,这是错误似乎指向的地方,但我确信它实际上与代理和 fetch 被 CORS 阻止有关。
const jwt = require('jsonwebtoken');
const secret = 'mysecretsshhh';

const withAuth = (req, res, next) => 
  const token = 
      req.body.token ||
      req.query.token ||
      req.headers['x-access-token'] ||
      req.cookies.token;

  if (!token) 
    res.status(401).send('Unauthorized: No token provided');
   else 
    jwt.verify(token, secret, function(err, decoded) 
      if (err) 
        res.status(401).send('Unauthorized: Invalid token');
       else 
        req.email = decoded.email;
        next();
      
    );
  


module.exports = withAuth;
这是我的身份验证组件,其中的错误也指向
import React,  Component  from 'react';
import  Redirect  from 'react-router-dom';


//withAuth is a high-order component which takes in a component to protect 
export default function withAuth(ComponentToProtect) 
  return class extends Component 
    constructor() 
      super();
      this.state = 
        loading: true,
        redirect: false,
      ;
    

    async componentDidMount() 
      fetch('http://localhost:8080/api/checktoken', 
        credentials: 'include',
        mode: 'cors'
      )
        .then(res => 
          if (res.status === 200) 
            this.setState( loading: false );
           else 
            const error = new Error(res.error);
            throw error;
          
        )
        .catch(err => 
          console.error(err);
          this.setState( loading: false, redirect: true );
        );
    


    render() 
      const  loading, redirect  = this.state;
      if (loading) 
        return null;
      
      if (redirect) 
        return <Redirect to="/login" />;
      
      return (
        <React.Fragment>
          <ComponentToProtect ...this.props />
        </React.Fragment>
      );
    
  

登录组件
import React,  Component  from 'react';

export default class Login extends Component  //impplicit vs explicit returns
  constructor(props) 
    super(props)
    this.state = 
      email : '',
      password: ''
    ;
  

  handleInputChange = (event) => 
    const  value, name  = event.target;
    this.setState(
      [name]: value
    );
  

  onSubmit = async (event) => 
    event.preventDefault();
    fetch('/api/authenticate', 
      method: 'POST',
      body: JSON.stringify(this.state),
      headers: 
        'Content-Type': 'application/json'
      
    )
    .then(res => 
      if (res.status === 200) 
        this.props.history.push('/');
       else 
        const error = new Error(res.error);
        throw error;
      
    )
    .catch(err => 
      console.error(err);
      alert('Error logging in please try again');
    );
  

  render() 
    return (
      <form onSubmit=this.onSubmit>
        <h1>Login Below!</h1>
        <input
          type="email"
          name="email"
          placeholder="Enter email"
          value=this.state.username
          onChange=this.handleInputChange
          required
        />
        <input
          type="password"
          name="password"
          placeholder="Enter password"
          value=this.state.password
          onChange=this.handleInputChange
          required
        />
        <input type="submit" value="Submit"/>
      </form>
    );
  

这是主要错误:

从源“http://localhost:3000”获取“http://localhost:8080/api/checktoken”的访问权限已被 CORS 策略阻止:“Access-Control-Allow-Origin”标头的值“http://localhost:8080”不等于提供的原产地。让服务器发送带有有效值的标头,或者,如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

它还说:

withAuth.jsx:17 GET http://localhost:8080/api/checktoken net::ERR_ABORTED 401(未授权)

在我的快递应用程序中,终端说它无法读取中间件中的令牌,我认为这也是由于 cors:

TypeError:无法读取未定义的属性“令牌” 在 withAuth (/Users/nancycollins/virtuload-beta/backend/middleware.js:6:16)

抱歉,如果这信息太多,我在这方面停留了太久,真的不知道还能做什么。

【问题讨论】:

与此同时,您可以在 chrome 上禁用 CORS 以进行开发***.com/questions/35432749/… 嘿,你找到解决办法了吗? 【参考方案1】:

更新:

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');

与:

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');

【讨论】:

谢谢,我做到了。不幸的是,我仍然收到错误 我遇到了很多错误,包括:加载资源失败:服务器响应状态为 500(内部服务器错误)withAuth.jsx:17 GET localhost:3003/api/checktoken500(内部服务器错误)和更多与faveicon有关..您认为这可能与开发模式有关吗?正如我的反应控制台所说“请注意,开发版本未优化。要创建生产版本,请使用 npm run build。”但我想处于开发模式,而不是生产.. 错误 500:您的后端现在似乎有错误。我认为这里的开发模式不是问题。 我也想过后端错误,但是当我用 Postman 测试后端时一切正常【参考方案2】:

我鼓励你在这些行之前做app.use(cors());

app.disable('x-powered-by');

app.use(function(req, res, next) 
  // Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
...

Express 将这些函数堆叠成一个“数组”,因此顺序很重要

希望它能解决您的问题。

【讨论】:

谢谢。我添加了这个,但仍然没有运气【参考方案3】:

参加聚会有点晚了,但我只想在这里留下我的答案,以防其他人遇到同样的问题。

这个想法是允许 CORS 请求到您的 Express 服务器。转到您的 server.js 文件所在的目录并运行:

npm install cors

然后在server.js 内添加以下行:

const cors = require('cors');

app.use(cors());

【讨论】:

以上是关于由于 CORS,无法在 Express 和 React 应用程序之间获取的主要内容,如果未能解决你的问题,请参考以下文章

如何在授权标头中将带有 fetch 和 cors 的 JWT 令牌发送到 Express 服务器?

无法使用 PUT 方法通过 CORS 和 Express 发送数据

使用 cors、express 和 google api 的 Node.js 服务器应用程序在 Azure 部署后无法正常工作

无法解决对 Express API 的 AJAX 调用的 CORS 错误

在 CORS 调用后,Express Session 不会持续存在

为啥我的 Express.js 后端的 CORS 设置不起作用?