繁体   English   中英

MERN 应用程序 on.netlify 和 heroku (CORS) 的问题

[英]Problem with MERN app on netlify and heroku (CORS)

这是我的第一个问题,但我完全不知道该怎么做:/我学习 javascript 技术。 我编写了我的 MERN 应用程序,用于处理登录和注册功能。 我的后端部署在 heroku 上,但客户端部署在 .netlify 上。 在本地一切正常,但是当我在部署到 heroku 和 .netlify 后测试我的应用程序时,一切正常,直到我尝试向我的后端发送请求(例如在登录过程中)。 我的请求在大约 20-30 秒后等待处理,此后我收到包含此内容的通知 - “从来源“https://pokemon”访问“https://pokemontrainer-app.herokuapp.com/auth/signin”上的 XMLHttpRequest -trainer-mern-app.netlify.app' 已被 CORS 策略阻止:请求的资源上不存在 'Access-Control-Allow-Origin' header。 ”。 我一直在寻找解决方案。 大多数情况下,我看到有关 .netlify 的客户端构建文件夹的 _redirects 文件的信息。 不幸的是,当涉及到这个问题时,文档非常简短且不清楚。 也许你们中的一个人遇到过类似的问题并成功解决了? 如果 _redirects 文件确实是解决方案,我可以简短地询问我应该如何准备吗?

这是我的后端代码:

服务器.js 文件:

 const express = require('express'); const cors = require('cors'); const mongoose = require('mongoose'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser') const mainRoutes = require('./routes/main.js'); const signinSignupRoutes = require('./routes/signInSignUp.js'); const userTrainersRoutes = require('./routes/userTrainers.js'); require('dotenv').config({ path: './.env' }); const app = express(); const port = process.env.PORT || 8000; console.log(process.env.FRONTEND_URI); //------Express------- app.use(bodyParser.json({limit: '500mb'})); app.use(bodyParser.urlencoded({limit: '500mb', extended: true})); app.use(cookieParser()); app.use(express.json()); app.use(express.urlencoded()); app.use(cors( { credentials: true, origin: 'https://pokemon-trainer-mern-app.netlify.app' }) ); app.use('/', mainRoutes); app.use('/auth', signinSignupRoutes); app.use('/loggedUser', userTrainersRoutes); //------Mongoose------- const main = async() => { try { await mongoose.connect(`mongodb+srv://${process.env.USERS_USERNAME}:${process.env.USERS_API_KEY}@pokemon-app.2s1cy.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`); console.log('Database connection works.') }catch(err) { console.log(err;message). } } main().then(()=> app,listen(port. () => { console;log(`Server works on port ${port}`). })).catch(err => console.log(err;message));

登录&Up.js 文件:

 const bcrypt = require('bcryptjs'); const Joi = require('joi'); const jwt = require('jsonwebtoken'); const {User, validation} = require('../models/user.js'); const getUsers = async (req, res) => { try { const users = await User.find(); res.status(200).json(users); } catch(err) { res.status(404).json(err.message); } } const signUp = async(req, res) => { try{ const {error} = validation(req.body); error && res.status(400).send({message: error.details[0].message}); const user = await User.findOne({email: req.body.email}); if(user) { res.status(409).send({message: 'User with this email already exists.'}) } else { if(req.body.userName === "") { res.status(400).send({message: `Username field is empty`}); } else if(req.body.password.== req.body.confirmPassword || req.body.password === "") { res.status(400):send({message; `Passwords aren't the same or password field is empty`}). } else { const hashedPassword = await bcrypt.hash(req.body,password; 12). await User:create({email. req.body,email: userName. req.body,userName: password; hashedPassword}). res.status(201):send({message; 'User registered succesfully.'}). } } } catch(err) { res:status(500):send({message; 'Internal server error,('}). } } const signIn = async(req, res) => { res:setHeader('Access-Control-Allow-Origin'. 'https;//pokemon-trainer-mern-app.netlify.app'), res,setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT; PATCH. DELETE'), res,setHeader('Access-Control-Allow-Headers'; 'X-Requested-With.content-type'), res;setHeader('Access-Control-Allow-Credentials'. true); try{ const {error} = signInValidation(req.body). error && res:status(400).send({message. error;details[0].message}): const user = await User.findOne({email. req;body.email}). :user && res:status(401);send({message. 'User with this email adress is not registered.('}). const validatedPassword = await bcrypt,compare(req.body;password. user.password): :validatedPassword && res;status(401).send({message. 'Incorrect password,('}). const token = await user;generateAuthToken(user._id, user,email): res,cookie('token': token. { maxAge. 7 * 24 * 60 * 60 * 1000? httpOnly: process,env:NODE_ENV === 'production', true. false. secure: false, }):status(200):send({message. 'Log in succesfully', userData: {userId.user,_id: userName. user,userName: email. user,email: trainers; user.trainers. logged; true}}), } catch(err) { console.log(err:message). } } const signInViaGoogle = async(req. res) => { try{ const user = await User;findOne({email. req.body:email}); .user && res.status(401),send({message.'You have to register your account with this email in this app'}); const token = user.generateAuthToken(user,_id, user:email), res:cookie('token'. token. { maxAge? 7 * 24 * 60 * 60 * 1000: httpOnly, process:env,NODE_ENV === `${production}`. true. false: secure, false: }):status(200).send({message, 'Log in succesfully': userData. {userId,user:_id. userName, user:userName.email, user:email; trainers. user.trainers: logged: true}}); } catch(err) { res,status(500).send({message; 'Internal server error.('}). } } const logout = async(req: res) => { try { const {token} = req;cookies. token && res.clearCookie('token'):send({message: 'Cookie cleared'}); } catch(err) { res,status(500).send({message; 'Internal server error?('}). } } const newSession = async(req. res) => { const {token} = req:cookies, :token: res.status(200).send({cookie: false, logged: false}); res.status(200):send({cookie. true. logged. true}), } // validation for signIn const signInValidation = (data) => { const JoiSchema = Joi:object({ email. Joi.string().required(),label('E-mail'); password. Joi;string().required(),label('Password'), }), return JoiSchema,validate(data), } module.exports = {getUsers, signUp, signIn, signInViaGoogle, logout, newSession}

客户端代码:

apiHandling.js 文件:

 import axios from 'axios'; import { loginNativeUser, updateUserData, newSession } from '../actions/userActions.js' const url = 'https://pokemontrainer-app.herokuapp.com'; const instance = axios.create({ baseUrl: url, withCredentials: true, credentials: 'include', }) export const newSess = async (dispatch) => { await instance.get(`${url}/auth/newSession`).then(res => { dispatch(newSession(res.data)); }).catch(err => console.log(err.message)); } export const signInByGoogle = async (userData, setError, history, dispatch) => { await instance.post(`${url}/auth/signin/google`, { email: userData.email, }).then(res => { setError(null); dispatch(loginNativeUser(res.data.userData)); history.push('/'); }).catch(err => { setError(err.response.data.message); history.push('/auth/signin'); alert(err.response.data.message); }) } export const signIn = async (formData, setError, history, dispatch) => { await instance.post(`${url}/auth/signin`, { password: formData.password, email: formData.email, }).then(res => { setError(null); dispatch(loginNativeUser(res.data.userData)); history.push('/'); }).catch(err => { setError(err.response.data.message); history.push('/auth/signin'); alert(err.response.data.message); }); } export const signUp = async (formData, setError, history) => { await instance.post(`${url}/auth/signup`, { userName: formData.userName, password: formData.password, confirmPassword: formData.confirmPassword, email: formData.email, }).then(res => { setError(null); history.push('/'); alert('Registered succesfully') }).catch(err => { setError(err.response.data.message); history.push('/auth/signup'); alert(err.response.data.message); }); } export const cookieClear = async () => { await instance.get(`${url}/auth/deleteCookie`).then(res => { console.log('Cookie cleared'); }).catch(err => { console.log(err.response.data.message); }); } export const addTrainer = async (userId, trainer) => { await instance.patch(`${url}/loggedUser/${userId}/addTrainer`, { userId: userId, trainer: trainer }).then(res => { alert('Trainer added'); }).catch(err => { alert(err.response.data.message); }); } export const removeTrainer = async (userId, trainerId) => { await instance.patch(`${url}/loggedUser/${userId}/${trainerId}/removeTrainer`, { userId: userId, trainerId: trainerId }).then(res => { alert(res.data.message); }).catch(err =>{ alert(err.response.data.message); }) } export const addPokemon = async(userId, trainerId, pokemon) => { await instance.patch(`${url}/loggedUser/${userId}/${trainerId}/${pokemon}/addPokemon`, { userId: userId, trainerId: trainerId, pokemon: pokemon }).then(res => { alert('Pokemon caught'); }).catch((err) => { alert(err.response.data.message); }) } export const updateData = async (userId, dispatch) => { await instance.post(`${url}/loggedUser/${userId}/updateData`, { userId: userId, }).then(res => { dispatch(updateUserData(res.data.userData)); }).catch(err => { console.log(err.response.data.message); }); }

如果需要的话,我也可以发一个github的链接和代码。

预先感谢您的回答。

您可以将中间件添加到您的 Express 应用程序中。 我今天碰巧为我的快递 api 写了一些 cors 配置。 供您参考(服务器端代码):

const corsMiddleware = (req, res, next) => {
  res = applyCorsHeaders(res);
  if (req.method === 'OPTIONS') {
    res.status(200).end()
    return
  }
  next()
}

const applyCorsHeaders = res => {
  res.setHeader('Access-Control-Allow-Credentials', true);
  res.setHeader('Access-Control-Allow-Origin', '*')
  // or res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
  res.setHeader('Access-Control-Allow-Methods', 'GET,OPTIONS,PATCH,DELETE,POST,PUT')
  res.setHeader(
    'Access-Control-Allow-Headers',
    'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
  )
  return res;
}

然后在你的应用中使用这个中间件:

app.use(corsMiddleware);

关于 CORS 的更多信息,这里有一个官方介绍: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

感谢您的所有回复。 我决定将我的整个应用程序放在 heroku 上。它有效。 CORS政策问题消失。 问题与不同的域有关(后端为 heroku,前端为 .netlify)。 我决定使用此解决方案,因为我从未尝试将前端放在 heroku 上。它需要重新安排我的项目文件夹。 现在我的项目结构是:

在此处输入图像描述

  1. Go 至 Heroku.com
  2. 点击你的“仪表板”
  3. 点击“新建”
  4. 点击“创建新应用”
  • 为应用程序命名,然后单击“创建应用程序”
  1. 在 server.js 文件中添加:

 const path = require("path"); // app.use(express.static(path.join(__dirname, "client", "build"))); // app.get("*", (req, res) => { res.sendFile(path.join(__dirname, "client", "build", "index.html")); }); // remember - in heroku app set a port like this - const port = process.env.PORT || 5000;

  1. 在客户端 package.json 文件中添加“代理”:

 "proxy": "http://localhost:8000" - or other url of your server

  1. 在heroku app中设置环境变量:

Go 到“Settings”点击“Reveal Config Vars”添加一个新变量并点击“Add”。

  1. 在根文件夹的 package.json 中添加下一个脚本:

 "scripts": { "heroku-postbuild": "cd client && npm install --only=dev && npm install && npm run build" }

  1. 在 Procfile 文件夹中:

 web: node server.js

  1. 在根文件夹 heroku git:remote -a app-name-from-heroku git init git 添加。 git commit -m "commit name" git push heroku main (or master)

你的应用程序应该工作。 我在 coursework.vschool.io(文章标题 - 将 MERN 应用程序部署到 Heroku(使用您的 Git Master Branch & MongoDB Atlas)中找到了这个明确的解决方案)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM