oauth_nest_demo/api/index.ts

130 lines
3.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import express from 'express';
import bodyParser from 'body-parser';
import * as path from 'path';
// 缓存 app 实例,避免每次冷启动都重新创建
let cachedApp: any;
async function bootstrap() {
if (!cachedApp) {
const expressApp = express();
// 动态解析 dist 目录路径
// 在 Vercel 环境中__dirname 是 /var/task/api
// NestJS 构建后文件在 dist/src 目录下
const distPath = path.resolve(__dirname, '..', 'dist', 'src', 'app.module');
console.log('Loading AppModule from:', distPath);
const { AppModule } = require(distPath);
const app = await NestFactory.create(
AppModule,
new ExpressAdapter(expressApp),
{ logger: ['error', 'warn', 'log'] },
);
// 配置 CORS
app.enableCors({
origin: true, // 允许所有来源
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: [
'Content-Type',
'Authorization',
'Accept',
'Origin',
'Referer',
'User-Agent',
],
});
// 尝试加载全局过滤器和拦截器
try {
const httpExceptionFilterPath = path.resolve(
__dirname,
'..',
'dist',
'src',
'common',
'filters',
'http-exception.filter',
);
const transformInterceptorPath = path.resolve(
__dirname,
'..',
'dist',
'src',
'common',
'interceptors',
'transform.interceptor',
);
const { HttpExceptionFilter } = require(httpExceptionFilterPath);
const { TransformInterceptor } = require(transformInterceptorPath);
app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalInterceptors(new TransformInterceptor());
} catch (error) {
console.log('Global filters/interceptors not loaded:', error.message);
}
// 全局验证管道
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}),
);
// Body parser 配置
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
// Swagger 文档
const config = new DocumentBuilder()
.setTitle('API 文档')
.setDescription('这是我的应用程序的 API 文档')
.setVersion('1.0')
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
// 配置 Swagger UI 使用 CDN 资源(解决 serverless 环境静态资源问题)
SwaggerModule.setup('docs', app, document, {
customCssUrl: [
'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.11.0/swagger-ui.css',
],
customJs: [
'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.11.0/swagger-ui-bundle.js',
'https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.11.0/swagger-ui-standalone-preset.js',
],
});
await app.init();
cachedApp = expressApp;
console.log('NestJS app initialized successfully');
}
return cachedApp;
}
// Vercel Serverless handler
export default async function handler(req: any, res: any) {
try {
console.log(`Request: ${req.method} ${req.url}`);
const app = await bootstrap();
app(req, res);
} catch (error) {
console.error('Handler error:', error);
res.status(500).json({
error: 'Internal Server Error',
message: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined,
});
}
}