如何将NestJS服务器从HTTP/1升级至HTTP/2?
NestJS HTTP/2 升级指南及问题解析
NestJS 是否内置 HTTP/2 支持?
NestJS 本身不直接实现 HTTP/2,但它依赖的底层 HTTP 服务器(Express 或 Fastify)支持 HTTP/2:
- Express: 需要借助额外工具(推荐 Node 原生
http2模块,替代已废弃的spdy)实现 HTTP/2 连接,但 Express 核心未原生适配 HTTP/2,请求对象仍会以 HTTP/1.1 格式暴露。 - Fastify: 原生支持 HTTP/2,无需额外依赖,且能直接提供 HTTP/2 兼容的请求/响应对象。
你当前问题的原因
你使用 spdy 创建 HTTP/2 服务器并挂载 Express 应用时,spdy 会将 HTTP/2 请求转换为 Express 能识别的 HTTP/1.1 请求格式。因此:
- 浏览器与服务器的连接确实是 HTTP/2(所以网络标签页显示正确)
- 但 Nest/Express 中拿到的
req对象是经过转换的 HTTP/1.1 版本,因此打印时显示 HTTP/1
正确升级到 HTTP/2 的两种方案
方案一:基于 Express + Node 原生 http2 模块(适配现有代码)
由于 spdy 已废弃,建议使用 Node 内置的 http2 模块。步骤如下:
- 无需额外安装依赖(
http2是 Node 核心模块) - 修改 bootstrap 函数:
import * as http2 from 'http2'; import { NestExpressApplication } from '@nestjs/platform-express'; import { ExpressAdapter } from '@nestjs/platform-express/adapters/express-adapter'; import * as fs from 'fs'; import { NestFactory, Logger } from '@nestjs/core'; import { AppModule } from './app.module'; import * as morgan from 'morgan'; import * as compression from 'compression'; import * as bodyParser from 'body-parser'; async function bootstrap() { const httpsOptions = { key: fs.readFileSync('/etc/secrets/server.key'), cert: fs.readFileSync('/etc/secrets/server.crt'), }; const expressApp = require('express')(); const app: NestExpressApplication = await NestFactory.create( AppModule, new ExpressAdapter(expressApp), { bufferLogs: true }, ); // 保留现有配置 const corsUrl = process.env.CORS_URL?.split(',') || []; app.enableCors({ origin: corsUrl, allowedHeaders: '*', methods: '*' }); const nestLogger = new Logger('HTTP REQUEST'); app.use(morgan(':method :url :status - :response-time ms', { stream: { write: (message: string) => nestLogger.log(message.trim()) }, })); app.use(compression()); app.use(bodyParser.json({ limit: '50mb' })); app.use(bodyParser.urlencoded({ limit: '50mb', extended: true })); app.use((req, res, next) => { res.setHeader('Content-Security-Policy', "script-src 'self'"); res.setHeader('X-XSS-Protection', '1; mode=block'); res.setHeader('X-Frame-Options', 'DENY'); res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); next(); }); await app.init(); // 创建 HTTP/2 服务器并挂载 Express 应用 const server = http2.createSecureServer(httpsOptions, expressApp); server.listen(8443, () => { console.log('Server running on https://localhost:8443 (HTTP/2)'); }); } bootstrap();
注意:此方案下,Express 请求对象仍会显示 HTTP/1.1,这是正常现象——连接层是 HTTP/2,但应用层仍用 HTTP/1.1 兼容格式。
方案二:基于 Fastify(推荐,原生 HTTP/2 支持)
Fastify 对 HTTP/2 有原生支持,能直接提供 HTTP/2 请求对象,步骤更简洁:
- 安装依赖:
npm install @nestjs/platform-fastify fastify fastify-morgan
- 修改 bootstrap 函数:
import { NestFactory, Logger } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication, } from '@nestjs/platform-fastify'; import { AppModule } from './app.module'; import * as fs from 'fs'; import fastifyMorgan from 'fastify-morgan'; async function bootstrap() { const httpsOptions = { key: fs.readFileSync('/etc/secrets/server.key'), cert: fs.readFileSync('/etc/secrets/server.crt'), allowHTTP1: true, // 可选:兼容 HTTP/1 请求 }; const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter({ https: httpsOptions, http2: true }), { bufferLogs: true }, ); // 配置 CORS const corsUrl = process.env.CORS_URL?.split(',') || []; app.enableCors({ origin: corsUrl, allowedHeaders: '*', methods: '*', }); // 替换 morgan 为 fastify-morgan const nestLogger = new Logger('HTTP REQUEST'); await app.register(fastifyMorgan(':method :url :status - :response-time ms', { stream: { write: (message: string) => nestLogger.log(message.trim()) }, })); // Fastify 内置压缩,无需额外 compression 中间件 app.register(require('@fastify/compress')); // 配置请求体大小限制 app.register(require('@fastify/formbody'), { bodyLimit: 52428800 }); // 50MB app.register(require('@fastify/json'), { bodyLimit: 52428800 }); // 设置安全头 app.addHook('onRequest', (request, reply, done) => { reply.header('Content-Security-Policy', "script-src 'self'"); reply.header('X-XSS-Protection', '1; mode=block'); reply.header('X-Frame-Options', 'DENY'); reply.header('X-Content-Type-Options', 'nosniff'); reply.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); done(); }); await app.listen({ port: 8443 }); console.log('Server running on https://localhost:8443 (HTTP/2)'); } bootstrap();
此方案下,req 对象会正确显示 HTTP/2 协议,且性能更优。
额外注意事项
- 确保 SSL 证书有效(HTTP/2 强制要求 HTTPS)
- 若使用反向代理(如 Nginx),需配置代理支持 HTTP/2 并正确转发协议信息
- Fastify 部分中间件与 Express 不兼容,需替换为 Fastify 生态对应组件
内容的提问来源于stack exchange,提问作者Muhammad Omer Hussain
相关产品推荐
相关产品推荐

