由于 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.jsconst 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 错误