netlify和heroku(CORS)上的MERN应用程序出现问题

oxf4rvwz  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(154)

这是我的第一个问题,但我完全诺奥知道该怎么做:/我学习javascript技术。我写了我的MERN应用程序,我在那里处理登录和注册功能。我的后端部署在heroku上,但客户端部署在netlify上。一切都在本地运行正常,但当我在部署到heroku和netlify后测试我的应用程序时,一切都正常,直到我尝试向后端发送请求(例如在登录过程中)。我的请求大约等待20-30秒,在这段时间后,我会收到以下内容的通知-“***访问XMLHttpRequest at ' https://pokemontrainer-app.herokuapp.com/auth/signin' from origin ' https:pokemon-trainer-mern-app.netlify.app'已被CORS策略阻止:请求的资源上没有“Access-Control-Allow-Origin”头。***"。我一直在寻找解决方案。我经常看到netlify的客户端构建文件夹的infos about _redirects文件。不幸的是,当涉及到这个问题时,文档非常简短且不清楚。也许你们中的某个人遇到了类似的问题并成功解决了它?如果_redirects文件确实是解决方案,我能简单地问一下我该如何准备吗?
这是我后端代码:
server.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));

登录.js文件(& U):

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链接。
提前感谢您的回答。

woobm2wo

woobm2wo1#

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

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

acruukt9

acruukt92#

谢谢大家的回复。我决定把我的整个应用程序放在heroku上。它工作正常。CORS策略问题消失了。问题与不同的域有关(heroku用于后端,netlify用于前端)。我决定使用这个解决方案,因为我从来没有尝试过把前端放在heroku上。它需要重新安排我的项目文件夹。现在我的项目结构是:
enter image description here
1.请访问Heroku.com
1.单击您的“控制面板”
1.单击“新建”
1.点击“创建新应用程序”

  • 给予应用程序命名,然后单击“创建应用程序”

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应用程序中设置环境变量:
转到“设置”,单击“显示配置变量”添加一个新变量,然后单击“添加”。
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应用程序名称-from-heroku git init git add . git commit -m“提交名称”git push heroku主文件夹(或主文件夹)
我在www.example.com找到了这个清晰的解决方案coursework.vschool.io(文章标题-部署MERN应用程序到Heroku(使用Git Master分支和MongoDBMap集)。

相关问题