Node + Express server not responding after OPTIONS preflight request

£可爱£侵袭症+ 提交于 2019-12-08 07:32:57

问题


I'm currently facing the following error, I'm developing an API in node js for let's say a virtual shop. An user, for getting its items in cart needs to be authenticated. The authentication is being handled via JWT, and im using passport module for that propose.

For the routes that require authentication, when the API is consumed using the 'Authentication' header with its correspondent 'JWT ey...' token, the server is not handling any request. Just responds to the OPTIONS preflight request and nothing more. I've tried consuming the /api/cart from an angular front end using httpClient, and the authorization header and getting the following error in the chrome devTools

As well i've tried using postman, sending the authorization header and couldn't get any response screen appears.

I'm logging the OPTIONS request headers. The following is the server response after hitting /api/cart with authorization header and it stops there.

 !OPTIONS
    { host: 'localhost:3000',
      connection: 'keep-alive',
      'access-control-request-method': 'GET',
      origin: 'http://localhost:4200',
      'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36',
      'access-control-request-headers': 'authorization,content-type',
      accept: '*/*',
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'en-US,en;q=0.9' }
    !OPTIONS
    OPTIONS /api/cart 200 1.288 ms - -

server.js

    const mongoose = require("mongoose");
    const express = require("express");
    const bodyParser = require("body-parser");
    const morgan = require("morgan");
    const passport = require("passport");
    const config = require("./config/database"); //Getting databas config file
    const User = require("./app/models/user"); //we're getting mongoose model
    const Product = require("./app/models/product");

    const app = express();
    const port = process.env.PORT || 3000;
    const routes = require("./app/routes/index");

    mongoose.connect(config.database);

    //bodyParser to get our request/response parameters
    app.use(
      bodyParser.urlencoded({
        extended: false
      })
    );
    app.use(bodyParser.json({ limit: "50mb" }));

    //log request to console
    app.use(morgan("dev"));
    app.use(passport.initialize());

    //pass passport for connfiguration
    require("./config/passport")(passport);

    //allow cors
    app.use(function(req, res, next) {
      res.setHeader("Access-Control-Allow-Origin", "*");
      res.setHeader(
        "Access-Control-Allow-Headers",
        "Origin, X-Requested-With, Content-Type, Accept, Authorization"
      );
      res.setHeader(
        "Access-Control-Allow-Methods",
        "GET, POST, OPTIONS, PUT, PATCH, DELETE"
      );
      if (req.method === "OPTIONS") {
        console.log("!OPTIONS");
        res.end();
      }
      next();
    });

    routes(app);

    app.listen(port);
    console.log("express app started on port " + port);

routes/index.js

const productApiRouter = require("./product.routes");
const userApiRouter = require("./user.routes");

module.exports = (app) => {
  app.use("/api", userApiRouter); //routes for users
  app.use("/products", productApiRouter); // routes for products
};

routes/user.routes

require('../models/user')
const express = require('express');
const passport = require('passport')

const isAuthenticated = require('../controllers/auth.controller')

const router = express.Router();

var userController = require('../controllers/user.controller');


router.get('/', userController.getUser)
router.get('/cart', passport.authenticate('jwt', {
    session: false,
    failWithError: true
  }),  userController.getCart)
router.post('/deletecart/:id', userController.deleteCartById)
router.post('/authenticate', userController.authenticate)
router.post('/signup', userController.signupUser)
router.get('/verify_email', userController.verifyEmailByUrl)
router.post('/addcart/:id', userController.addItemToCart)
router.post('/update_user', userController.updateUser)

module.exports = router;

controllers/user.controller.js get cart method

exports.getCart = (req, res) => {
  var token = getToken(req.headers);
  if (token) {
    var decoded = jwt.decode(token, config.secret);
    User.findOne(
      {
        email: decoded.email
      },
      function(err, user) {
        if (err) throw err;

        if (!user) {
          return res.status(404).send({
            success: false,
            message: "Not user found"
          });
        } else {
          var cart = user.itemsInCart;
          console.log(cart);
          var items = addItemCount.addItemCount(cart);
          console.log(items);
          res.status(200).send(JSON.stringify(items));
        }
      }
    );
  } else {
    console.log('Request ')
     res.status(403).send({
      success: false,
      message: "Unauthorized request"
    });
  }
};

config/passport ---> passport configuration

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const User = require('../app/models/user');
const config = require('./database');

//add a JWT strategy to our passport
module.exports = function(passport) {
    var opts = {};
    opts.jwtFromRequest = ExtractJwt.fromAuthHeaderWithScheme("jwt");
    opts.secretOrKey = config.secret;
    passport.use('jwt', new JwtStrategy(opts, function(jwt_payload, done) {
        User.findOne({
            id: jwt_payload.id //try to find a user given jwt_payload.id
        }, function(err, user) {
            if (err) {
                return done(err, false);
            }
            if (user) {
                done(null, user);
            } else {
                done(null, false)
            }
        });
    }));
}

getToken function

 var getToken = function(headers) {
     if (headers && headers.authorization) {
         var parted = headers.authorization.split(' ');
         if (parted.length === 2) {
             return parted[1];
         } else {
             return null;
         }
     } else {
         return null;
     }
 };

 module.exports = getToken

回答1:


After struggling the problem I found the reason the server is not working for request with authorization token.

For a NodeJS server, the header's max size for http requests is 80KB. ref: http_parser.h nodejs source code

#define HTTP_MAX_HEADER_SIZE (80*1024)

In the mentioned requests in the question, I'm attaching some Base64 encoded images to the JWT Token making it way more bigger than the header size permitted by the NodeJS server for http requests.

So the solution is to make sure that the headers size for an http request is below 80K threshold.



来源:https://stackoverflow.com/questions/48876574/node-express-server-not-responding-after-options-preflight-request

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