網站搜尋

node.js - Express Response.send() 拋出 TypeError


我有這個簡單的 Express 代碼:

const api = Router()

api.post('/some-point', async (req, res, next) => {
  const someStuffToSend = await Promise.resolve("hello");
  res.json({ someStuffToSend });
})

它在我的開發環境中運作良好,但在生產環境中我收到以下錯誤:

TypeError: argument entity must be string, Buffer, or fs.Stats
    at etag (/[...]/node_modules/etag/index.js:83:11)
    at generateETag ([...]/node_modules/express/lib/utils.js:280:12)
    at ServerResponse.send ([...]/node_modules/express/lib/response.js:200:17)
    at ServerResponse.json ([...]/node_modules/express/lib/response.js:267:15)
    at api.post (/the/code/above)

我在 node_modules/etag/index.js:83:11 檢查並看到

if (!isStats && typeof entity !== 'string' && !Buffer.isBuffer(entity)) {
  throw new TypeError('argument entity must be string, Buffer, or fs.Stats')
}

在這段程式碼之前,我加入了一個 printf 來檢查實體的類型:

console.log("Entity contains", entity, "is of type", typeof entity, "with constructor", entity.constructor, "and is it a buffer?", Buffer.isBuffer(entity))

這使我得到了以下輸出:

Entity contains <Buffer 7b 22 70 72 65 64 69 63 74 69 6f 6e 5f 69 64 22 3a 22 63 4b 57 41 64 41 46 43 77 6e 55 43 22 2c 22 69 6e 69 74 69 61 6c 5f 70 72 65 64 69 63 74 69 6f ... > is of type object with constructor function Buffer(arg, encodingOrOffset, length) {
  if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
    return new Buffer(arg, encodingOrOffset, length)
  }

  // Common case.
  if (typeof arg === 'number') {
    if (typeof encodingOrOffset === 'string') {
      throw new Error(
        'If encoding is specified then the first argument must be a string'
      )
    }
    return allocUnsafe(this, arg)
  }
  return from(this, arg, encodingOrOffset, length)
} and is it a buffer? false

所以看起來這個實體是個緩衝區,但沒有被認作如此。如果我把測試註解掉,它會在另一個位置崩潰

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be one of type string or Buffer
    at ServerResponse.end (_http_outgoing.js:747:13)
    at ServerResponse.send ([...]/node_modules/express/lib/response.js:221:10)
    at ServerResponse.json ([...]/node_modules/express/lib/response.js:267:15)
    at api.post (/the/code/above)

如果你在 /node_modules/express/lib/response.js:221:10 查看,你會看到

this.end(chunk, encoding);

編碼來自上面幾行(第189行,我用 printf 檢查過)

chunk = Buffer.from(chunk, encoding)

我可以修改這個庫來讓它工作,但我懷疑是某個壞掉的 node_modules 資料夾。然而,即使在執行 rm package-lock.json; rm -rf node_modules; npm i 之後,錯誤依然存在。

如果有任何解決這個問題的線索,我將非常感激。

以下是我的版本號碼:

  • node 9.8.0(也試過 8.4.0),使用 nvm 本地安裝
  • npm 5.6.0
  • express 4.16.3
  • ts-node 5.0.1
  • typescript 2.7.2

編輯 1

  • 用更簡單的方式取代 async 調用
  • 指定快速版本

編輯 2

我移除了 node_modules 資料夾,然後逐一使用 npm i 安裝套件:

npm i aws-sdk body-parser bunyan check-types deepcopy duck-type express fast-csv glob handlebars http-auth md5 moment moment-timezone multer node-stream object-path randomstring

仍然出現相同的錯誤。

編輯 3

補充有關環境的更多資訊。

編輯 4

好的,弄明白了。這是與 ts-node 配置相關的問題。我是用…啟動我的伺服器的

ts-node --harmony_async_iteration -r tsconfig-paths/register ./src/index.ts

在我的 tsconfig.json 中加入以下幾行:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2017",
    "lib": [ "es2017", "esnext.asynciterable" ],
    "noImplicitAny": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "dist",
    "baseUrl": ".",
    "pretty": true,
    "paths": {
      "*": [
        "*", "src/*", "src/types/*",
        "node_modules/*"
      ]
    }
  },
  "include": [ "src/**/*" ]
}

由於命令列中的 -r tsconfig-paths/register,tsconfig.json 中指定的路徑被加載,包括 paths['*'] 中的 "node_modules/*"。

我不確定原因,但看起來這導致 node_modules 中的庫被加載了兩次,從而破壞了基於構造函數的類型檢查(例如 instanceof)。

問題

我不太確定完全理解那個原因。有什麼線索嗎?

答案#1

我在使用 typeorm 時遇到了非常相似的問題,後來在使用 express 時也遇到過。提示就在這個對話中。我的解決方法是從 paths 中去掉 *。

答案#2

我收到了這個錯誤,

TypeError: argument entity must be string, Buffer, or fs.Stats
    at etag (/[...]/node_modules/etag/index.js:83:11)
    at generateETag ([...]/node_modules/express/lib/utils.js:280:12)
    .....

我正在嘗試運行一個 Express 專案,並使用 Webpack 作為打包工具,

當我在 webpack 中將目標設為 'node' 時,我的錯誤得以解決

module.exports = (env) => {
    return {
      //....
      target: "node",
      //....,
      plugins: [
        // new NodePolyfillPlugin() // Don't add this plugin
       ]
    
    }
}

並確保不要將 NodePolyfillPlugin 添加為插件