HEROKU上的CORS问题

时间:2018-12-20 20:24:29

标签: javascript node.js express heroku cors

我在Heroku上使用CORS遇到问题。

这是我在服务器上的代码

import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
require('dotenv').config()

import filmRoutes from './api/routes/films'
import userRoutes from './api/routes/users'

const app = express()

const DBNAME = process.env.DB_USER 
const DBPASSWORD = process.env.DB_PASS


mongoose.connect(`mongodb://${DBNAME}:${DBPASSWORD}@ds157422.mlab.com:57422/filmbase`, {useNewUrlParser: true})

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", '*');
  res.header("Access-Control-Allow-Credentials", true);
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
  next();
});

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.use('/films', filmRoutes)
app.use('/users', userRoutes)


export default app;

这是我的发帖请求

  CheckLogin = () => {
    const data = {
      name: this.state.formInput.login.value,
      password: this.state.formInput.password.value
    }
    axios.post('https://whispering-shore-72195.herokuapp.com/users/login', data)
    .then(response=>{
      console.log(response);
      const expirationDate = new Date(new Date().getTime() + response.data.expiresIn * 1000)
      localStorage.setItem('token', response.data.token)
      localStorage.setItem('expirationDate', expirationDate)
      this.context.loginHandler()
    })
    .catch(err=>{
      console.log(err)
    })

    console.log(data);
  }

这是错误

  

在以下位置访问XMLHttpRequest   原产地的“ https://whispering-shore-72195.herokuapp.com/users/login”   “ https://mighty-citadel-71298.herokuapp.com”已被CORS屏蔽   策略:“访问控制允许来源”标头不存在   请求的资源。

我尝试了很多方法,什么也没做……有什么主意吗?

8 个答案:

答案 0 :(得分:0)

您已经跨过https://whispering-shore-72195.herokuapp.comhttps://mighty-citadel-71298.herokuapp.com上的原始域

您可以尝试npm cors package作为中间件而不是自定义中间件。 CORS软件包允许您进行多个配置,并且非常易于使用。

简单用法(启用所有CORS请求)

import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import cors from 'cors';
require('dotenv').config()

import filmRoutes from './api/routes/films'
import userRoutes from './api/routes/users'

const app = express()

const DBNAME = process.env.DB_USER 
const DBPASSWORD = process.env.DB_PASS


mongoose.connect(`mongodb://${DBNAME}:${DBPASSWORD}@ds157422.mlab.com:57422/filmbase`, {useNewUrlParser: true})

/*app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", '*');
  res.header("Access-Control-Allow-Credentials", true);
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
  next();
});*/

app.use(cors()); // <---- use cors middleware

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.use('/films', filmRoutes)
app.use('/users', userRoutes)


export default app;

编辑:

我已经测试了从https到服务器的客户端呼叫登录,并且该服务器可以正常工作而没有CORS问题。也许您已经成功修复了它。

我在StackBlitz上尝试了简单方法,它已经成功运行。

检查时,您可以尝试登录https://js-53876623.stackblitz.io/并查看“网络”选项卡,并查看OPTIONS (200 status)POST (404 not found)(因为我在您的数据库中不认识任何用户)

Edit Dec 22 2018-7:18 PM

我已经在本地尝试过您的代码,也许您没有测试并处理所有错误,不幸的是,这使您的应用程序崩溃了。

我已经运行了您的代码,发现问题可能是jsonwebtoken错误:

  

错误:secretOrPrivateKey必须具有一个值

请尝试使用process.env.JWT_KEY || 'Require key here!!!',,并在您的环境中设置JWT_KEY或使用||作为服务器上的默认密钥。

也许可以解决您的问题。

建议:

对于您的代码,我有一些建议:

  • 请使用User.findOne()代替User.find()
  • 请使用app.use(cors());
  • 在服务器上运行时,
  • jsonwebtoken应该使用异步而不是同步。

答案 1 :(得分:0)

这是我的源代码

服务器

userController.js

import mongoose from 'mongoose';
import User from '../models/user';
import bcrypt from 'bcrypt';
import jsw from 'jsonwebtoken'

export default {

  async send(req, res ,next){
    User.find({name: req.body.name})
    .exec()
    .then(user=>{
      if(user.length >= 1){
        return res.status(409).json({
          message: 'User exist'
        });
      }
      else{
        bcrypt.hash(req.body.password, 10, (err,hash)=>{
          if(err){
            return res.status(500).json({
              error: err
            });
          }else{
            const user = new User({
              _id: new mongoose.Types.ObjectId(),
              name: req.body.name,
              password: hash
            });
            user
            .save()
            .then(result=>{
              console.log(result);
              res.status(201).json({
                message: 'user created'
              });
            })
            .catch(err=>{
              console.log(err)
              res.status(500).json({
                error: err
              })
            })
          }
        })
      }
    })
  },

  async login(req, res, next){
    User.find({name: req.body.name})
    .exec()
    .then(user=>{
      if(user.length < 1){
        return res.status(404).json({
          message: 'user exist'
        })
      }
      bcrypt.compare(req.body.password, user[0].password, (err, result)=>{
        if(err){
          return res.status(404).json({
            message: 'bcrypt failed'
          })
        }
        if(result){
          const time = '1'
          const token = jsw.sign({
            name: user[0].name,
            iserId: user[0]._id
          },process.env.JWT_KEY,
          {
            expiresIn: `${time}h`
          }
          );
          return res.status(200).json({
            message: 'auth success',
            token: token,
            expiresIn: time
          })
        }
        return res.status(404).json({
          message: 'Auth failed'
        })
      })
    })
    .catch(err=>{
      res.status(500).json({
        error: err
      })
    })
  }

}

app.js

import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
require('dotenv').config()

import filmRoutes from './api/routes/films'
import userRoutes from './api/routes/users'

const app = express()

const DBNAME = process.env.DB_USER 
const DBPASSWORD = process.env.DB_PASS


mongoose.connect(`mongodb://${DBNAME}:${DBPASSWORD}@ds157422.mlab.com:57422/filmbase`, {useNewUrlParser: true})

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", '*');
  res.header("Access-Control-Allow-Credentials", true);
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
  next();
});

app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

app.use('/films', filmRoutes)
app.use('/users', userRoutes)


export default app;

客户

LoginPades.js

import React from 'react';
import './LoginPages.css';
import axios from 'axios'

import AuthContext from '../../../auth-context';
import Input from '../../Input/Input';

class Login extends React.Component {
  static contextType = AuthContext;
  state={
    formInput:{
      login:{
        elementType: 'input',
        elementConfig: {
          type: 'text',
          placeholder: 'Login'
        },
        Value:''
      },
      password:{
        elementType: 'input',
        elementConfig:{
          type: 'text',
          placeholder: 'Password'
        },
        Value:'',
      }
    }
  }

  inputChangeHandler = (event, id) => {
    let value = event.target.value;
    const updateState = {
      ...this.state.formInput
    }
    const updateElement = {
      ...updateState[id]
    }
    updateElement.value = value;
    updateState[id] = updateElement

    this.setState({
      formInput: updateState
    })
  }

  CheckLogin = () => {
    const data = {
      name: this.state.formInput.login.value,
      password: this.state.formInput.password.value
    }
    axios.post('https://whispering-shore-72195.herokuapp.com/users/login', data)
    .then(response=>{
      console.log(response);
      const expirationDate = new Date(new Date().getTime() + response.data.expiresIn * 1000)
      localStorage.setItem('token', response.data.token)
      localStorage.setItem('expirationDate', expirationDate)
      this.context.loginHandler()
    })
    .catch(err=>{
      console.log(err)
    })

    console.log(data);
  }

  render(){
    const inputsArray = [];
    for (let key in this.state.formInput){
      inputsArray.push({
        id: key,
        config: this.state.formInput[key]
      })
    }

    let inputs =(
      <>
      {inputsArray.map(inputElement=>(
        <Input
        className='input-lodig-password'
        key={inputElement.id} 
        elementType={inputElement.config.elementType}
        elementConfig={inputElement.config.elementConfig}
        value={inputElement.value}
        changed={(event)=>this.inputChangeHandler(event, inputElement.id)}
        />
      ))}
      </>
    ) 


    return(
      <div className='login'>
        <div className='card'>
          <div className='spider'>
            {/* <img src='http://www.officialpsds.com/images/thumbs/Spiderman-Logo-psd59240.png' alt='pajak'/> */}
          </div>
          <p className='opis'>Zaloguj sie do groty rozpusty</p>
          <form className='login-inputy'>
             {inputs}
          </form>
            <button className='btn-login' onClick={this.CheckLogin}>Zaloguj sie</button>
        </div>
      </div>
    )
  }
}

export default Login

答案 2 :(得分:0)

router / user.js

import express from 'express';
import userController from '../controllers/usersController';
import {catchAsync} from '../moddlewares/errors';


const router = express.Router();

router.post('/signup',catchAsync(userController.send))
router.post('/login', catchAsync(userController.login))

export default router

模型/user.js

import mongoose from 'mongoose'

const userSchema = mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  name: {type: String, required: true},
  password: {type: String, required: true}
})

const user = mongoose.model('User', userSchema);

export default user

catchAsync.js

export function catchAsync(cb){
  return (req,res,next)=>{
    cb(req,res,next).catch(err=>next(err))
  }
}

答案 3 :(得分:0)

我也遇到过同样的问题,我认为您的问题不是CORS。您可以测试服务器日志吗?以我为例,我遇到了包装问题,这就是我得到503的原因,也没有“ Access-Control-Allow-Origin”标头,CORS错误。当我解决软件包和jwt问题时,我的CORS问题就解决了!。

答案 4 :(得分:0)

您需要确定是否确实是 CORS 问题或您的API代码已损坏。

如果是 CORS 问题,请按照上面的建议处理后端代码中的 CORS 或使用cors软件包。

但是,问题经常是,您的代码正在中断,而您却并不知道,这是很多时候。例如,就我而言,我没有将nodemon添加到依赖项中,而我的start脚本依赖于Heroku找不到的nodemon。因此,您的代码可能在dev中工作正常,但在prod中中断。

您可以通过以下方法在Heroku中查找代码的哪些部分:

  1. 在浏览器开发工具中检查网络。如果响应如下所示是503 Service Unavailable,则再次表明您的代码已中断。enter image description here
  2. 打开您遇到问题的项目后,
  3. 在Heroku仪表板的右上角找到更多按钮。 enter image description here
  4. 在单击更多按钮后,从显示的下拉菜单中
  5. 选择查看日志。现在,您应该看到跟踪的日志。如果没有看到错误,请尝试对代码进行一些小的更改,然后在再次查看日志的同时进行重新部署。就我而言,如下所示,nodemon是崩溃的原因。 enter image description here

答案 5 :(得分:0)

您的问题与 CORS Heroku 服务器的服务不可用有关。由于是免费服务,每小时调用次数限制为50次。请按照答案中的建议尝试使用您自己的CORS服务器作为中间件或自行托管CORS-Anywhere

答案 6 :(得分:0)

在 Heroku 中部署后,我遇到了同样的问题,在代码的不同点使用 console.log(),我可以看到这样的错误消息:'RangeError Maximum call stack size exceeded...'。 这是一个 NodeJs 错误,我通过在 package.json 底部添加此代码来修复它:

“决议”:{ “FS-电容器”:“3.0.0” }

告诉我它是否适合您。

答案 7 :(得分:-2)

我在使用 Heroku 和我的后端时遇到了类似的问题,它现在托管在 vercel 中。

如果您正在使用环境变量,请确保在您的 vercel 应用程序中设置这些变量,或者如果您在其他任何地方托管,请先检查一下。环境变量!