From 2a86d9f5e47cfe14004041c451e43c902fb415ab Mon Sep 17 00:00:00 2001 From: admin <572701190@qq.com> Date: Sat, 2 May 2026 03:29:46 +0800 Subject: [PATCH] Raise report upload request size limits - Configure NestJS with an explicit JSON and urlencoded body parser limit controlled by API_BODY_LIMIT. - Set the default API body limit to 100mb for report HTML, key frames, template images, and Data URL file uploads. - Add a matching Nginx client_max_body_size 100m limit so Docker web proxy no longer rejects large report saves first. - Document the new request body limit in README, deployment docs, progress notes, environment example, and AGENTS context. - Rebuild and verify Docker web/api with a large report save through the Nginx /api proxy. --- .env.example | 1 + AGENTS.md | 2 ++ README.md | 3 ++- docker-compose.yaml | 1 + docs/deployment.md | 3 ++- docs/progress.md | 2 ++ nginx.conf | 1 + server/src/main.ts | 6 +++++- 8 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 661ddad..04388a4 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ # Backend API development defaults. API_PORT=3100 +API_BODY_LIMIT="100mb" CORS_ORIGIN="http://localhost:3001,http://localhost:4002" DATABASE_URL="postgresql://surclaw:surclaw_dev_password@localhost:5433/surclaw?schema=public" SESSION_SECRET="change-me-in-production" diff --git a/AGENTS.md b/AGENTS.md index 1814963..ad08ab0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -307,6 +307,8 @@ npm run test:e2e 后端第一阶段骨架。当前已实现健康检查、认证接口、报告 API、报告媒体关系、模板 API、字段库 API、用户/部门 API、设置 API、通用文件/签名文件 API、AI 代理、讯飞语音代理、PrismaService 和权限策略;前端登录、报告、模板、字段库、模板图片资源、用户管理、系统设置、签名上传、AI 对话和语音听写已接入后端接口/代理。新增后端功能时优先按模块拆分:`auth`、`reports`、`templates`、`library`、`users`、`files`、`settings`、`ai`、`speech`。 +API 默认 JSON/urlencoded 请求体上限为 `100mb`,由 `API_BODY_LIMIT` 控制;Nginx 同步配置了 `client_max_body_size 100m`,用于承载迁移期报告 HTML、图片/关键帧和通用文件 Data URL 上传。 + ### `server/prisma/schema.prisma` PostgreSQL 数据模型。当前覆盖 `Tenant`、`Department`、`User`、`UserSession`、`AppSession`、`Report`、`ReportMedia`、`ReportHistory`、`Template`、模板部门授权、`FileResource`、`SystemSetting` 和 `AuditLog`。Prisma 7 连接配置在根目录 `prisma.config.ts` 中。 diff --git a/README.md b/README.md index c64584c..a7efc2f 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ cp .env.example .env.local 当前环境变量: - `API_PORT`:NestJS API 监听端口,本地直接运行默认 `3100`;Docker Compose 暴露到宿主机的默认端口是 `3002`。 +- `API_BODY_LIMIT`:NestJS JSON/urlencoded 请求体上限,默认 `100mb`,用于报告 HTML、图片/关键帧和文件 Data URL 上传。 - `CORS_ORIGIN`:允许携带 Cookie 访问 API 的前端来源。 - `DATABASE_URL`:PostgreSQL 连接串。Docker Compose 暴露到宿主机的默认端口是 `5433`,容器内部仍使用 `db:5432`。 - `SESSION_SECRET`:后端 Session Cookie 签名密钥,生产环境必须替换。 @@ -237,7 +238,7 @@ docker-compose down - `web` 服务使用 Nginx 托管前端 `dist/`。 - `api` 服务运行 NestJS 后端,并把上传文件目录挂载到 `uploads_data` volume。 - `db` 服务运行 PostgreSQL 16。 -- `nginx.conf` 已配置 SPA 路由回退和 `/api` 反向代理。 +- `nginx.conf` 已配置 SPA 路由回退、`/api` 反向代理和 `100m` 请求体上限。 - `nginx.conf` 已支持 `/api/speech/iat` WebSocket upgrade。 ## 当前限制 diff --git a/docker-compose.yaml b/docker-compose.yaml index b082a76..4890fd1 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -20,6 +20,7 @@ services: restart: unless-stopped environment: API_PORT: 3100 + API_BODY_LIMIT: 100mb CORS_ORIGIN: http://localhost:4002,http://localhost:3001 DATABASE_URL: postgresql://surclaw:surclaw_dev_password@db:5432/surclaw?schema=public SESSION_SECRET: change-me-in-production diff --git a/docs/deployment.md b/docs/deployment.md index d7abba3..2d93739 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -59,6 +59,7 @@ AI 和语音密钥由后端 Settings API 保存并由代理使用,前端不再 后端新增变量: - `API_PORT`:API 监听端口。本地直接运行默认 `3100`;Docker Compose 暴露到宿主机的默认端口是 `3002`。 +- `API_BODY_LIMIT`:API JSON/urlencoded 请求体上限,默认 `100mb`。报告正文、关键帧、模板图片和通用文件上传仍可能携带 Data URL,调小会导致保存或上传出现 `request entity too large`。 - `CORS_ORIGIN`:允许跨域携带 Cookie 的前端来源。 - `DATABASE_URL`:PostgreSQL 连接串。Docker Compose 暴露到宿主机的默认端口是 `5433`,容器内部仍使用 `db:5432`。 - `SESSION_SECRET`:Session Cookie 签名密钥。 @@ -87,7 +88,7 @@ docker-compose up -d --build - `Dockerfile` 使用 Node 构建 `dist/`。 - 运行阶段使用 `nginx:alpine` 托管静态文件。 - `Dockerfile.server` 构建并运行 NestJS API。 -- `nginx.conf` 已配置 SPA 路由回退和 `/api` 反向代理。 +- `nginx.conf` 已配置 SPA 路由回退、`/api` 反向代理和 `100m` 请求体上限。 ## 部署边界 diff --git a/docs/progress.md b/docs/progress.md index 5931f52..8c5515b 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -17,6 +17,7 @@ - 用户管理、部门管理员约束和部门模板授权已优先接入后端 Users/Departments API;签名上传和模板图片资源已通过 Files API 写入后端文件资源。 - 系统设置、抽帧策略、AI Provider、语音参数和默认模板已优先接入 Settings API,只有开发/显式回退模式下才保留本地缓存回退。 - Docker/Nginx 静态部署配置已存在。 +- Docker/Nginx 与 NestJS API 已把请求体上限统一到 `100mb`,避免图文报告和文件 Data URL 上传触发默认 413。 - 开发端口已调整为 `3001`。 - 已补充 Vitest 测试框架和核心功能单元/组件测试。 - 已补充功能盘点,区分真实功能、外部集成、前端演示和预留项。 @@ -77,3 +78,4 @@ | 2026-05-02 | 新增前端组件结构文档,梳理页面组件、公共组件、API/Auth/Utils 分层、数据流和大组件拆分边界。 | | 2026-05-02 | 将默认“腹腔镜胆囊切除术报告”后端 seed 与前端默认报告内容对齐,并把系统设置重置改为演示模式恢复出厂设置。 | | 2026-05-02 | 修正报告草稿后端校验和保存失败提示,补充麦克风启动前置检查。 | +| 2026-05-02 | 增加 Nginx 和 NestJS 请求体上限配置,修复大图文报告保存 `request entity too large`。 | diff --git a/nginx.conf b/nginx.conf index 6844f2f..5dd6ce6 100644 --- a/nginx.conf +++ b/nginx.conf @@ -6,6 +6,7 @@ map $http_upgrade $connection_upgrade { server { listen 80; server_name localhost; + client_max_body_size 100m; root /usr/share/nginx/html; index index.html; diff --git a/server/src/main.ts b/server/src/main.ts index 802c1b2..46bed37 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -1,6 +1,7 @@ import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; import cookieParser from 'cookie-parser'; +import { json, urlencoded } from 'express'; import session from 'express-session'; import { AppModule } from './app.module.js'; import { AuthService } from './auth/auth.service.js'; @@ -11,10 +12,13 @@ import { attachSpeechProxy } from './speech/speech.gateway.js'; import { SpeechService } from './speech/speech.service.js'; const bootstrap = async () => { - const app = await NestFactory.create(AppModule); + const app = await NestFactory.create(AppModule, { bodyParser: false }); const port = Number(process.env.API_PORT ?? 3100); + const bodyLimit = process.env.API_BODY_LIMIT ?? '100mb'; app.setGlobalPrefix('api'); + app.use(json({ limit: bodyLimit })); + app.use(urlencoded({ extended: true, limit: bodyLimit })); app.useGlobalFilters(new ApiExceptionFilter()); app.enableCors({ origin: process.env.CORS_ORIGIN?.split(',') ?? ['http://localhost:3001', 'http://localhost:4002'],