【问题标题】:TypeError: Router.use() requires a middleware function but got a undefined with two middlewares involvedTypeError:Router.use() 需要一个中间件函数,但有一个未定义的函数,涉及两个中间件
【发布时间】:2021-09-18 06:43:01
【问题描述】:

我必须在我的 ts-node 应用程序上运行测试,并且在运行测试时遇到了这个问题,对于上下文,应用程序的路由必须通过两个中间件,一个是授权,另一个是有效请求,我有这个配置路线

const router = express.Router();
router.use('/cars', requiredAuthorization, requiredHeadersValidator, cars);


router.use('/healthcheck', healthcheck());

export default router;

我在运行测试时收到此错误:

  ● Test suite failed to run

TypeError: Router.use() requires a middleware function but got a undefined

   8 | const cars = require('../routes/cars');
   9 |
> 10 | router.use('/cars', requiredAuthorization, requiredHeadersValidator, cars);
     |        ^
  11 | router.use('/healthcheck', healthcheck());
  12 |
  13 | export default router;

  at Function.use (node_modules/express/lib/router/index.js:458:13)
  at Object.<anonymous> (src/web-server/routes/index.ts:10:8)
  at Object.<anonymous> (src/web-server/index.ts:7:1)
  at Object.<anonymous> (src/web-server/middlewares/required-authorization.ts:3:1)
  at Object.<anonymous> (src/web-server/middlewares/__tests__/required-authorization.test.ts:4:1)

我在这里和其他部分尝试了几乎所有答案,但似乎都没有帮助(在每个路由文件中都有一个导出默认路由器行)

更新

中间件是:

import { Request, Response, NextFunction } from 'express';
import { StatusCodes } from 'http-status-codes';
import { autho } from '../index';

const requiredAuthorization = async (req: Request, res: Response, next: NextFunction) => {

  if (!req.headers.authorization) {
    return res.status(StatusCodes.FORBIDDEN)
    .json({
      errors: [{
        status: StatusCodes.FORBIDDEN, detail: 'Unauthorized'
      }]
    });
  }

  let idToken;
  if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
    idToken = req.headers.authorization.split('Bearer ')[1];
  } else {
    return res.status(StatusCodes.FORBIDDEN)
    .json({
      errors: [{
        status: StatusCodes.FORBIDDEN, detail: 'Unauthorized'
      }]
    });
  }

  try {
    await autho.auth().verifyIdToken(idToken);
    next();
    return;
  } catch (error) {
    return res.status(StatusCodes.FORBIDDEN)
    .json({
      errors: [{
        status: StatusCodes.FORBIDDEN, detail: 'Unauthorized'
      }]
    });
  }

};

export default requiredAuthorization;

和:

import { Request, Response, NextFunction } from 'express';
import { ReasonPhrases, StatusCodes } from 'http-status-codes';

const requiredHeadersValidator = (req: Request, res: Response, next: NextFunction) => {
  if (req.header('Content-Type') !== 'application/vnd.api+json') {
    return res.status(StatusCodes.UNSUPPORTED_MEDIA_TYPE)
      .json({
        errors: [{
          status: StatusCodes.UNSUPPORTED_MEDIA_TYPE, detail: ReasonPhrases.UNSUPPORTED_MEDIA_TYPE
        }]
      });
  }

  if (req.header('Accept') !== 'application/vnd.api+json') {
    return res.status(StatusCodes.NOT_ACCEPTABLE)
      .json({
        errors: [{
          status: StatusCodes.NOT_ACCEPTABLE, detail: ReasonPhrases.NOT_ACCEPTABLE
        }]
      });
  }

  next();
};

export default requiredHeadersValidator;

进口:

import * as express from 'express';
import * as healthcheck from 'express-healthcheck';
import requiredAuthorization from '../middlewares/required-authorization';
import requiredHeadersValidator from '../middlewares/required-headers-validator';
import cars from './cars';

cars.ts 文件:

import * as express from 'express';
import { BrandController } from '../controllers/brand-controller';
import { ModelController } from '../controllers/model-controller';
import { VehicleController } from '../controllers/vehicle-controller';

const router = express.Router();

// brands
router.get('/brands', BrandController.findAll);
router.get('/brands/:id', BrandController.findById);
router.get('/brands/:id/models', BrandController.findModelsByBrandId);
router.post('/brands', BrandController.create);
router.patch('/brands/:id', BrandController.updateBrandById);
router.delete('/brands/:id', BrandController.deleteBrandById);

// models
router.get('/models', ModelController.findAll);
router.get('/models/:id', ModelController.findById);
router.get('/models/:id/brands', ModelController.findBrandByModelId);
router.post('/models', ModelController.create);
router.patch('/models/:id', ModelController.updateModelById);
router.delete('/models/:id', ModelController.deleteModelById);

// vehicles
router.get('/:plate', VehicleController.findByPlate);

export default router;

【问题讨论】:

  • 能分享一下 requiredAuthorization 和 requiredHeadersValidator 的代码吗?
  • 是的,我更新了问题
  • 谢谢,还有你是如何将它们导入到使用它们的地方的,请。还有第一个代码 sn-p 中的 cars 变量。
  • 添加在问题的末尾
  • 谢谢,我指的是汽车文件本身(这个'./cars'),你能分享文件内容吗?

标签: node.js typescript ts-node


【解决方案1】:

我偶然和一位同事解决了这个问题,他的 IDE 以不同的顺序自动完成了文件的导入,更准确地说,requiredAuthorization 是路由器和测试中的最后一个导入,并且测试通过了没有问题。

import * as express from 'express';
import * as healthcheck from 'express-healthcheck';
import requiredHeadersValidator from '../middlewares/required-headers-validator';
import cars from './cars';
import requiredAuthorization from '../middlewares/required-authorization';

像这样错误消失了(测试是用 Jest 进行的),我想这可能有助于将来有人考虑导入顺序,以防出现一些奇怪的行为

P.D:如果有人知道为什么订单会影响这种行为,我很乐意知道

【讨论】:

    猜你喜欢
    • 2019-04-21
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2020-07-14
    • 1970-01-01
    • 2020-12-27
    相关资源
    最近更新 更多