【问题标题】:Cannot fetch between Express and React apps due to CORS由于 CORS,无法在 Express 和 React 应用程序之间获取
【发布时间】: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)

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

【问题讨论】:

标签: node.js reactjs express proxy fetch


【解决方案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());

【讨论】:

    猜你喜欢
    • 2017-07-15
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 2021-08-01
    • 1970-01-01
    相关资源
    最近更新 更多