首页 > 解决方案 > 部署在 Heroku 上的 Nodejs 服务器。请求失败

问题描述

我有一个迷你论坛应用程序,包括传递给包的身份验证、帖子、评论和网关。在本地,所有请求都可以正常工作。但是在部署到 Heroku 之后,只有 GET 请求有效,其他请求失败。

日志中的错误:[HPM] 代理请求 anaalamed-mini-forum.herokuapp.com/api/login 到 http://localhost:4000/ [ECONNRESET] 时发生错误(https://nodejs.org/api/errors .html#errors_common_system_errors

这是我的第一步,所以...谢谢你的帮助

网关/index.ts

import { app } from 'api-server';
import { createProxyMiddleware } from 'http-proxy-middleware';
import fetch from 'node-fetch';
import * as express from 'express';
import * as path from 'path';

app.use(['/api/comments', '/api/posts'], async function checkAuth(req, res, next) {
try {
    const response = await fetch('http://localhost:4000/api/me', { headers: { cookie: req.headers.cookie } })
    const user = await response.text();
    const setCookie = response.headers.get('set-cookie')
    if (setCookie) {
        res.append('set-cookie', setCookie);
    }
    req.headers.user = user;
} catch {
    req.headers.user = '';
}
next();
})
app.use('/api/comments', createProxyMiddleware({ target: 'http://localhost:4002', changeOrigin: true }));
app.use('/api/posts', createProxyMiddleware({ target: 'http://localhost:4001', changeOrigin: true }));
app.use(['/api/users', '/api/me', '/api/register', '/api/login', '/api/logout'], createProxyMiddleware({ target: 'http://localhost:4000', changeOrigin: true }));

// serve UI
app.use(express.static(path.resolve(__dirname, '../../ui/build')));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '../../ui/build', 'index.html'));
});

app.listen(process.env.PORT || 8080, () => console.log('Gateway app is running! on Port: ', process.env.PORT))

日志

2021-08-06T10:19:59.365861+00:00 heroku[router]: at=info method=GET path="/api/comments?entity=61068acdbe91bb0f7145ccf3" host=anaalamed-mini-forum.herokuapp.com request_id=5f0d58d4-fd3f-495a-b86c-6494fcc8ebe1 fwd="5.29.13.122" dyno=web.1 connect=0ms service=82ms status=304 bytes=183 protocol=https
2021-08-06T10:19:59.391481+00:00 heroku[router]: at=info method=GET path="/api/comments?entity=61069bf0be91bb0f7145ccf4" host=anaalamed-mini-forum.herokuapp.com request_id=49fbacde-0fc5-491b-81e5-1538eda0747b fwd="5.29.13.122" dyno=web.1 connect=0ms service=80ms status=304 bytes=181 protocol=https
2021-08-06T10:19:59.332485+00:00 heroku[router]: at=info method=GET path="/api/comments?entity=610689fdbe91bb0f7145ccf2" host=anaalamed-mini-forum.herokuapp.com request_id=f75eab61-bfe5-43b4-8a53-c6757ff4972c fwd="5.29.13.122" dyno=web.1 connect=1ms service=81ms status=304 bytes=183 protocol=https
2021-08-06T10:19:59.364159+00:00 app[web.1]: [start:comments] ::ffff:127.0.0.1 - - [06/Aug/2021:10:19:59 +0000] "GET /api/comments?entity=61068acdbe91bb0f7145ccf3 HTTP/1.1" 304 - "https://anaalamed-mini-forum.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:19:59.366881+00:00 app[web.1]: [start:gateway] ::ffff:10.13.124.73 - - [06/Aug/2021:10:19:59 +0000] "GET /api/comments?entity=61068acdbe91bb0f7145ccf3 HTTP/1.1" 304 - "https://anaalamed-mini-forum.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:19:59.388509+00:00 app[web.1]: [start:comments] ::ffff:127.0.0.1 - - [06/Aug/2021:10:19:59 +0000] "GET /api/comments?entity=61069bf0be91bb0f7145ccf4 HTTP/1.1" 304 - "https://anaalamed-mini-forum.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:19:59.390036+00:00 app[web.1]: [start:gateway] ::ffff:10.15.14.173 - - [06/Aug/2021:10:19:59 +0000] "GET /api/comments?entity=61069bf0be91bb0f7145ccf4 HTTP/1.1" 304 - "https://anaalamed-mini-forum.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:19:59.609755+00:00 app[web.1]: [start:gateway] ::ffff:10.32.238.58 - - [06/Aug/2021:10:19:59 +0000] "GET /icon.png HTTP/1.1" 200 157694 "https://anaalamed-mini-forum.herokuapp.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:19:59.616941+00:00 heroku[router]: at=info method=GET path="/icon.png" host=anaalamed-mini-forum.herokuapp.com request_id=4b32c985-21e1-46cf-b2b6-63ece2e09e57 fwd="5.29.13.122" dyno=web.1 connect=1ms service=12ms status=200 bytes=158004 protocol=https
2021-08-06T10:21:31.302014+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=POST path="/api/login" host=anaalamed-mini-forum.herokuapp.com request_id=3ff0432f-90f0-4e71-92b3-48d21c1966f3 fwd="5.29.13.122" dyno=web.1 connect=1ms service=30000ms status=503 bytes=0 protocol=https
2021-08-06T10:21:31.310593+00:00 app[web.1]: [start:gateway] [HPM] Error occurred while proxying request anaalamed-mini-forum.herokuapp.com/api/login to http://localhost:4000/ [ECONNRESET] (https://nodejs.org/api/errors.html#errors_common_system_errors)
2021-08-06T10:21:31.321710+00:00 app[web.1]: [start:gateway] ::ffff:10.39.170.242 - - [06/Aug/2021:10:21:31 +0000] "POST /api/login HTTP/1.1" 504 - "https://anaalamed-mini-forum.herokuapp.com/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:21:31.323846+00:00 app[web.1]: [start:auth] ::ffff:127.0.0.1 - - [06/Aug/2021:10:21:31 +0000] "POST /api/login HTTP/1.1" - - "https://anaalamed-mini-forum.herokuapp.com/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36"
2021-08-06T10:21:31.334977+00:00 app[web.1]: [start:auth] BadRequestError: request aborted
2021-08-06T10:21:31.334980+00:00 app[web.1]: [start:auth]     at IncomingMessage.onAborted (/app/node_modules/raw-body/index.js:231:10)
2021-08-06T10:21:31.334981+00:00 app[web.1]: [start:auth]     at IncomingMessage.emit (events.js:400:28)
2021-08-06T10:21:31.334981+00:00 app[web.1]: [start:auth]     at abortIncoming (_http_server.js:566:9)
2021-08-06T10:21:31.334981+00:00 app[web.1]: [start:auth]     at socketOnClose (_http_server.js:559:3)
2021-08-06T10:21:31.334982+00:00 app[web.1]: [start:auth]     at Socket.emit (events.js:412:35)
2021-08-06T10:21:31.334982+00:00 app[web.1]: [start:auth]     at TCP.<anonymous> (net.js:675:12)

根目录下的 package.json

{
  "name": "mini-forum",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "workspaces": [
    "apps/*",
    "packages/*"
  ],
  "scripts": {
    "dev": "concurrently \"npm run dev:*\"",
    "dev:auth": "npm run dev --workspace=apps/auth",
    "dev:posts": "npm run dev --workspace=apps/posts",
    "dev:gateway": "npm run dev --workspace=apps/gateway",
    "db": "docker-compose --file ./mongo-compose.yaml up",
    "start": "node start.js",
    "start:comments": "cd apps/comments && npm start",
    "start:auth": "cd apps/auth && npm start",
    "start:posts": "cd apps/posts && npm start",
    "start:gateway": "cd apps/gateway && npm start",
    "postinstall": "node postinstall.js",
    "build": "cd apps/ui && npm install && npm run build"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "concurrently": "^6.0.2",
    "cors": "^2.8.5",
    "nodemon": "^2.0.7"
  },
  "engines": {
    "npm": "7.10.0"
  },
  "devDependencies": {
    "prettier": "2.3.1"
  }
}

开始.js

const concurrently = require('concurrently');

// concurrently([{command: 'npm run start:*', env: process.env}])
concurrently([{command: 'npm run start:*'}])

所以'npm start' 会启动所有的应用程序:auth、posts、comments 和 gateway。所有的应用程序也有自己的 package.json 并且可以单独启动。

标签: node.jsexpressheroku

解决方案


你背后的原因是createProxyMiddleware什么?一旦您的应用程序在 Heroku 服务器上运行,这将失败,因为它将请求代理到localhost:4002/ localhost:4001,这意味着应用程序将请求转发到另一个“本地”服务,该服务将在同一服务器实例上运行(它们不会)。

在本地对您而言,它可能有效,因为您在测试应用程序时在本地运行了其他服务,但 Heroku 上不存在这些其他服务。

#1 使用procfile

您可以使用procfile让多个 nodejs 进程在 1 个 dyno 下运行。正如这个答案中已经说明的那样,这可能看起来像这样:

web: node service1.js & node service2.js & node service3.js

但是,由于您的每个服务都需要单独的端口,这可能对您不起作用,因为 heroku 只为每个测功机打开 1 个动态分配端口(process.env.PORT在运行时可用)。如果我是正确的,这是无法改变的。

#2 使用多个应用程序/测功机

我相信使用 heroku 的目的(建立微服务架构)是为每个服务创建 1 个应用程序,每个服务至少 1 个 dyno。这样做的大专业人士将能够相互独立地扩展每个服务。然后只需使用分配的子域来调用它们(app1.herokuapp.com, app2.herokuapp.com, ... )。此外,您最终将拥有独立指标,并且可以独立更新测功机。这基本上是微服务背后的想法。

#3 暂时不要使用微服务

查看您的示例,您可能不需要将其拆分为多个服务。考虑创建一个单一的 API,如果你刚开始,它可能更容易管理。


推荐阅读