CORS problems on HEROKU

人走茶凉 提交于 2021-01-23 04:48:55

问题


I have problem with CORS on Heroku.

This is my code on server

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;

This is my post request

  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);
  }

This is ERROR

Access to XMLHttpRequest at 'https://whispering-shore-72195.herokuapp.com/users/login' from origin 'https://mighty-citadel-71298.herokuapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I tried a lot of methods and nothing... any idea?


回答1:


You've cross origin domain on https://whispering-shore-72195.herokuapp.com from origin https://mighty-citadel-71298.herokuapp.com

You can try npm cors package as middleware instead of your custom middleware. CORS package allows you multiple configure and it's very easy to use.

Simple Usage (Enable All CORS Requests)

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;

Edit:

I've test your client call login to your server from https and it's working without CORS problem. Maybe you had fixed it successfully.

I've tried with simple on StackBlitz and it's working successfully.

You can try login https://js-53876623.stackblitz.io/ and view network tab when inspecting and see OPTIONS (200 status) and POST (404 not found) (because I don't know any user in your database)

Edit Dec 22 2018 - 7:18 PM

I've tried your code on my local, maybe you hadn't tested and handled all error, it makes your app crash unfortunately.

I've run your code and noticed the problem maybe jsonwebtoken error:

Error: secretOrPrivateKey must have a value

Please tried with process.env.JWT_KEY || 'Require key here!!!',, and set your JWT_KEY on your environment or use || as default key on server.

Maybe it will fix your problem.

Recommends:

I have some recommends for your code:

  • Please use User.findOne() instead of User.find()
  • Please use app.use(cors());
  • jsonwebtoken should use Asynchronous instead of Sync when run on server.



回答2:


I have deal with same problem, I think your problem is not CORS. Can you test your server logs. In my case i had a package problem and thats way i was getting 503 also No 'Access-Control-Allow-Origin' header, CORS error. When i fix package and jwt problem my CORS problem solved!.




回答3:


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

model/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))
  }
}



回答4:


This is my souce code

Server

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;

Client

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



回答5:


You need to determine if it is indeed a CORS issue or your API code is breaking.

If it's a CORS issue, handle CORS in your backend code like it's been suggested above or use the cors package.

However, often times than not, the issue is that your code is breaking and you just didn't know. In my case, for instance, I didn't add nodemon to the dependencies and my start script is dependent on nodemon which Heroku could not find. So it's possible that your code works fine in dev but breaks in prod.

Here's how you can find what part of your code is breaking within Heroku:

  1. Inspect your network in your browser dev tool. If the response is 503 Service Unavailable as indicated below, that is an indication again that your code is breaking.
  2. Locate the More button on the top right corner of your Heroku dashboard once you open the project you're having issues with.
  3. Select View Logs from the dropdown that shows up after you click the More button. You should now see the log of the track trace. If you don't see the error, try making any small change in your code and redeploying while watching the log again. In my case, as indicated below, the nodemon was the reason for the crash.



回答6:


Your issue is related to Service Unavailable from the CORS Heroku server. Since it is a free service, the number of calls per hour is limited to 50. Please try to use your own CORS server as a middleware as suggested in the answers or self host CORS-Anywhere



来源:https://stackoverflow.com/questions/53875548/cors-problems-on-heroku

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!