You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Fastify的NestJS应用配置HTTP/HTTPS端口遇问题求助

问题描述

我本地运行一个基于Fastify的容器化NestJS应用,需要配置外部第三方服务向应用的部分端点推送数据。目前应用通过HTTP监听3000端口,但第三方服务采用客户端认证,他们提供了PFX文件和密码,我想用这些配置一个监听3333端口的HTTPS端口。本地测试时,Thunderclient和Postman均报错:

  • Postman: 客户端网络套接字在安全TLS连接建立前断开
  • Thunderclient: 连接被对等方强制关闭

我请求的地址是https://localhost:3333/endpoint/。

以下是实现HTTPS之前的main.ts代码:

import { NestFactory } from '@nestjs/core';
import { NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
import {
  utilities as nestWinstonModuleUtilities,
  WinstonModule,
} from 'nest-winston';
import * as winston from 'winston';
import * as winstonDailyRotateFile from 'winston-daily-rotate-file';

async function bootstrap() {
  
  const app = await NestFactory.create<NestFastifyApplication>(AppModule, { logger: globalLogger });
  await app.startAllMicroservices();
  await app.listen(3000);

  process.on('uncaughtException', function (err) {
    globalLogger.error(JSON.stringify(err, null, 2))
    globalLogger.log("UNCAUGHT EXCEPTION: Node NOT Exiting...");
  });
}

const globalLogger = WinstonModule.createLogger({ 
   // ... 日志配置
})

bootstrap();
已尝试方案

我参考了NestJS官方文档、相关GitHub问题和Stack Overflow讨论,尝试了多种配置,当前的main.ts代码如下:

import { NestFactory } from '@nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
import { httpsModule } from './httpsmodule/httpsmodule.module';
import {
  utilities as nestWinstonModuleUtilities,
  WinstonModule,
} from 'nest-winston';
import * as winston from 'winston';
import * as winstonDailyRotateFile from 'winston-daily-rotate-file';
import { readFileSync, accessSync, constants } from 'fs';

async function bootstrap() {
  
  try {    
    const userAuthCertificateFilePath = "/src/ssl/UserCloudAuth.p12";
    accessSync(userAuthCertificateFilePath, constants.F_OK | constants.R_OK)
    const certificatePassword = "somePassword"

    const userAuthCertificateFilePath = process.env.CERTIFICATE_FILE_PATH;
    const certificatePassword = process.env.CERTIFICATE_PASSWORD;

    const httpsOptions = {
      pfx: readFileSync(userAuthCertificateFilePath),
      passphrase: certificatePassword
    }

    const httpApp = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    { logger: globalLogger }
    );
    await httpApp.startAllMicroservices();   

    const httpsApp = await NestFactory.create<NestFastifyApplication>(
      httpsModule,
      new FastifyAdapter({
        https: httpsOptions
      })
    );

    await httpsApp.startAllMicroservices();

    await httpApp.listen(3000); 
    await httpsApp.listen(3333);

    process.on('uncaughtException', function (err) {
      globalLogger.error(JSON.stringify(err, null, 2))
      globalLogger.log("UNCAUGHT EXCEPTION: Node NOT Exiting...");
    });
  } catch (error) {
    globalLogger.error(`Main: ${error}`)
  }
}

const globalLogger = WinstonModule.createLogger({
  // ... 日志配置
})

bootstrap();
解决方案

1. 修复变量重复定义问题

当前代码重复定义了userAuthCertificateFilePath和certificatePassword,直接覆盖了硬编码值,若环境变量未设置会读取undefined路径引发错误。调整为:

// 优先使用环境变量,无值时 fallback 到默认配置
const userAuthCertificateFilePath = process.env.CERTIFICATE_FILE_PATH || "/src/ssl/UserCloudAuth.p12";
const certificatePassword = process.env.CERTIFICATE_PASSWORD || "somePassword";

2. 验证证书文件路径与权限

容器内路径可能和本地不一致,确保/src/ssl/UserCloudAuth.p12在容器中存在,且应用进程拥有读取权限。可在启动容器时挂载本地证书目录到对应路径,或在代码中增加路径存在性校验的错误提示。

3. 用单Nest实例监听多端口(推荐)

无需创建两个独立Nest应用实例,Fastify支持单实例同时监听HTTP和HTTPS端口,可共享模块、中间件和配置:

async function bootstrap() {
  const globalLogger = WinstonModule.createLogger({ 
    // ... 日志配置
  });

  // 创建HTTP适配器与Nest应用
  const httpAdapter = new FastifyAdapter();
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    httpAdapter,
    { logger: globalLogger }
  );
  await app.startAllMicroservices();

  // 配置HTTPS服务器选项
  const httpsOptions = {
    pfx: readFileSync(userAuthCertificateFilePath),
    passphrase: certificatePassword
  };
  const httpsServer = httpAdapter.getInstance().createServer(httpsOptions);
  
  // 监听HTTP和HTTPS端口,指定0.0.0.0允许外部访问
  await app.listen(3000, '0.0.0.0');
  await new Promise((resolve) => httpsServer.listen(3333, '0.0.0.0', resolve));

  process.on('uncaughtException', function (err) {
    globalLogger.error(JSON.stringify(err, null, 2))
    globalLogger.log("UNCAUGHT EXCEPTION: Node NOT Exiting...");
  });
}

4. 检查HTTPS模块配置

若坚持使用独立的httpsModule,需确保该模块正确注册了需要暴露的端点,且无错误的中间件、守卫配置导致连接中断。

5. 本地测试排查

  • 用lsof -i :3333确认端口未被其他进程占用
  • 若PFX证书为自签名或私有CA颁发,需在Postman/Thunderclient中导入证书信任,避免TLS验证失败
  • 执行curl -v https://localhost:3333/endpoint/查看详细连接日志,定位具体错误点

内容的提问来源于stack exchange,提问作者Abeer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 04:39:53