高度混乱的 express.Router() 问题

Highly confusing express.Router() issue

我使用 serverless framework 部署了一个使用 NestJS 构建的大型应用程序。我这样做已经有一段时间了,一切都很好。几天前,我不得不更新到 Nestjs 7,当我的应用程序部署到 aws 时,我在引导应用程序时遇到了很多问题。经过无数次令人沮丧的尝试来解决这个问题后,它似乎实际上与 Nestjs/serverless 引导过程完全无关并且 apollo-server-express 无法访问快速路由器 - 失败并出现错误:

express_1.default.Router is not a function

最后我意识到,当我直接导入 express 并尝试访问 express.Router() 时,我遇到了同样的问题。所以我做了一个很简单的测试:

lambda.ts:

import { Context, Handler } from "aws-lambda";
import express from "express";

export const handler: Handler = async (event: any, context: Context) => {
  console.log("Import express:", express);
  console.log("Test express app: ", express());
  console.log("Test router:", express.Router());

  /* express.Router() ->
  ERROR TypeError: express_1.default.Router is not a function at 
  /var/task/dist/lambda.js:19:51 at Generator.next (<anonymous>) at 
  /var/task/dist/lambda.js:8:71 at new Promise (<anonymous>) at 
  __awaiter (/var/task/dist/lambda.js:4:12) at exports.handler (/var/task/dist/lambda.js:16:39) at 
  Runtime.handler (/var/task/serverless_sdk/index.js:9:131872) at 
  Runtime.handleOnce (/var/runtime/Runtime.js:66:25)
  */
};

如前所述,由于评论中的错误而失败。以下是其他文件:

serverless.yml:

service: xxxxx
app: xxxx
tenant: xxxxx

plugins:
  - serverless-pseudo-parameters
  - serverless-prune-plugin
  - serverless-deployment-bucket

provider:
  name: aws
  runtime: nodejs12.x
  region: eu-west-1
  stage: dev
  timeout: 29
  memorySize: 3008
  deploymentBucket:
    name: ${self:service}-${self:custom.currentStage}-deployment-bucket
    serverSideEncryption: AES256

custom: ${file(./serverless-common.yml):custom}
package:
  include:
    - ./dist/**
  exclude:
    - node_modules/aws-sdk/**

functions:
  index:
    handler: ./dist/lambda.handler
    name: bm-${self:custom.currentStage}-express-test
    events:
      - http:
          path: "/{proxy+}"
          method: POST

package.json:

{
  "name": "@xxx/XXXXXX",
  "version": "0.1.13",
  "dependencies": {
    "express": "4.17.1"
  },
  "devDependencies": {
    "serverless-deployment-bucket": "1.1.1",
    "serverless-prune-plugin": "1.4.2",
    "serverless-pseudo-parameters": "2.5.0",
    "ts-node": "^8.7.0",
    "tsconfig-paths": "^3.7.0",
    "tslint": "5.12.1",
    "tslint-config-prettier": "^1.18.0",
    "typescript": "^3.8.3"
  }
}

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@root/*": ["src/*"]
    },
    "module": "commonjs",
    "moduleResolution": "node",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es6",
    "sourceMap": true,
    "outDir": "dist",
    "esModuleInterop": true
  },
  "include": ["*"],
  "exclude": ["**/node_modules/**/*", "dist"]
}

我想强调的是,此代码只有在部署到 lambda 后才会失败。它在本地运行良好,这表明打包过程可能有问题,但 zip 文件包含正确的代码和依赖项。

在缩小范围之前,我已经研究了这个问题很多年了。如果任何 body 能够阐明以上内容,将不胜感激,因为它显然阻碍了我。

非常感谢


更新:

好的,看来如果我:

import Router from 'express/lib/router'

然后我得到一个路由器实例。这与 express 索引应该导出的实例相同。

所以我很接近,但这感觉不对,我没有改变任何东西,我觉得我有某种不正确的模块配置或其他东西。

那我为什么不能express.Router()。任何想法将不胜感激。


更新:

最后我修补了 apollo-server-express 以便它从 lib/router 获取路由器实例,然后一切都按预期工作。

我显然不想这样做,所以我真的需要弄清楚是什么原因造成的。

已修补 ApolloServer.js:https://gist.github.com/TreeMan360/8dc8373ffebe2b24ff51df42090fcb52


更新:

另一个相关的问题是 headers 作为响应的一部分返回 body 例如:

HTTP/1.1200OKX-Powered-By: ExpressAccess-Control-Allow-Origin: *Content-Type: application/json;charset=utf-8Content-Length: 155ETag: W/"9b-mbrRmusN4ADjvBFA5aFJNLyRMHs"Date: Sat,
04Apr202014: 35: 09GMTConnection: keep-alive{
  "data": {
    "memberLoginHook": {
      "id": "1bb4ca87-d9f6-4ccb-a2a4-0249b19699b3",
      "occupation": "C3PO",
      "positions": [
        {
          "id": "f4deaf82-ad87-472b-82ab-c78d08138526"
        }
      ]
    }
  }
}

同样值得注意的是,我发现其他人也有同样的问题: https://forum.serverless.com/t/highly-confusing-express-router-issue/10987/8

我知道是什么触发了这个问题,非常奇怪的错误有非常奇怪的解决方案。 尝试禁用 Serverless Framework Enterprise(如果已启用),您只需将租户和应用程序行注释到 serverless.yml 文件中,然后再次部署该应用程序。 我认为serverless-sdk的最新版本存在错误。