node.js - Node + Express 服务器在 OPTIONS 预检请求后未响应

标签 node.js express cors passport.js

我目前面临以下错误,我正在 Node js 中为虚拟商店开发一个 API。用户为了将其商品放入购物车,需要进行身份验证。身份验证是通过 JWT 处理的,我使用 Passport 模块来实现该建议。

对于需要身份验证的路由,当使用“Authentication” header 及其对应的“JWT ey...” token 使用 API 时,服务器不会处理任何请求。仅响应 OPTIONS 预检请求,仅此而已。 我尝试使用 httpClient 从角度前端使用/api/cart 和授权 header ,并在 chrome devTools 中收到以下错误

chrome console log

我也尝试过使用 postman ,发送授权 header ,但出现无法获得任何响应屏幕。

我正在记录 OPTIONS 请求 header 。以下是使用授权 header 点击/api/cart 后的服务器响应,并在那里停止。

 !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 - -

服务器.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);

路线/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
};

路线/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;

Controller /user.controller.js 获取购物车方法

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 配置

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函数

 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

最佳答案

在解决这个问题之后,我找到了服务器无法处理带有授权 token 的请求的原因。

对于 NodeJS 服务器,http 请求的 header 最大大小为 80KB。引用:http_parser.h nodejs source code

#define HTTP_MAX_HEADER_SIZE (80*1024)

在问题中提到的请求中,我将一些 Base64 编码的图像附加到 JWT token ,使其比 NodeJS 服务器允许的 http 请求 header 大小更大。

因此,解决方案是确保 http 请求的 header 大小低于 80K 阈值。

关于node.js - Node + Express 服务器在 OPTIONS 预检请求后未响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48876574/

相关文章:

javascript - 在特定路由处理程序提供响应后调用通用路由处理程序

node.js - 使用 tfjs-node 时添加类型

mysql - node.js forEach 不阻塞

Node.js 崩溃了!语法错误 : Unexpected token ILLEGAL

javascript - Node 和 DialogFlow 错误 : UnhandledPromiseRejectionWarning: TypeError: sessionClient. projectAgentSessionPath 不是函数

使用 Aurelia Fetch 客户端时出现 CORS 错误

javascript - 非阻塞 setTimeout

javascript - 查找表和整数范围 - javascript

nginx - 推荐的 CORS 允许和公开 header

Spring 4. 2's native Global CORS support won' t 与 CAS filterProcessesUrl 一起使用