Files
doodle-store/docs/v3.5/Server基础设置.md

8.4 KiB
Raw Permalink Blame History

Doodle Store Server 基础设置

更新日期:2026-10-15。已实现基础配置、日志、中间件、Swagger、微信登录、Prisma 账户查询与 JWT 守卫。

后续业务接入见 用户鉴权与登录设计;服务端登录模式和 reason 已接入,小程序恢复及 Web Cookie 会话仍是目标设计。当前接口与验证说明见 服务端登录接入说明。

参考 atlas-seller-kit/apps/api 的应用工厂、结构化日志、requestId、请求体限制、默认鉴权与错误处理。保持本项目 NestJS 11 和 /api/v1 契约,不复制卖家工作台的多租户、Redis、对象存储或业务模块。

1. 启动与环境变量

从 doodle-store 根目录执行 pnpm dev。服务只读取 apps/server/.env,不向上搜索根目录的 Compose .env;部署环境变量优先于 .env。应用工厂不自行监听端口,main 负责读取配置和启动,测试使用临时端口。

开发命令通过 apps/server/scripts/dev.mjs 启动 Nest watch,在收到实际监听成功的通知后,输出 Swagger: <完整地址> 并使用系统默认浏览器打开一次。热更新不重复打开;SWAGGER_ENABLED=false 时只提示文档已关闭。链接使用实际监听 IP/端口,通配地址转换为本机地址。通知独立于日志级别;打开浏览器失败只提示手动访问,不终止服务。pnpm start 保留服务端启动行为,不自动打开浏览器,server_started 结构化日志增加 swagger_url。

新环境先复制 apps/server/.env.example 为 apps/server/.env,设置 JWT_SECRET。生成随机密钥的示例命令:

node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"

真实密钥仅写入受控环境配置,不提交仓库。当前本机已生成独立开发密钥;测试使用测试专用密钥,生产必须另行生成。

配置 默认 / 要求
NODE_ENV development;允许 development/test/production
HOST / PORT 127.0.0.1 / 8800;端口须为 1~65535 整数
LOG_LEVEL info;允许 error/warn/info/debug
API_BODY_LIMIT_BYTES 1048576,即 1 MiB;允许 1 KiB~10 MiB
SWAGGER_ENABLED 未设置时开发/测试 true,生产 false;生产不要照搬开发示例中的 true
CORS_ORIGINS 空列表;逗号分隔的完整 HTTP(S) origin,不接受 * 或路径
TRUSTED_PROXY_CIDRS 空列表;按部署显式设置代理 IP/CIDR,不使用 true 或跳数
JWT_SECRET 必填,至少 32 字节;拒绝空值、过短或 change-me 占位值
JWT_ISSUER / JWT_AUDIENCE doodle-store / doodle-mini
JWT_EXPIRES_IN_SECONDS 86400,即 24 小时;允许 60~604800 秒
WECHAT_MINI_APP_ID 小程序 AppID;必填,必须与 AppSecret 成对提供
WECHAT_MINI_APP_SECRET 必填;无默认密钥,仅服务端持有

微信配置写入 apps/server/.env,不写根目录 Compose .env。服务端通过 ServerConfig.wechatMiniAppId/wechatMiniAppSecret 读取;两项去除首尾空白后校验非空且不含内部空白,错误不回显实际值。登录时使用 code2Session 验证身份,启动校验不代表已验证微信凭据真实有效。AppSecret 与 JWT_SECRET 是独立密钥,不得混用、下发或输出到日志。

DATABASE_URL 现在必填,必须为 PostgreSQL URL 且使用 public schema;Prisma 单应用连接池最多 5 条连接,连接超时 2 秒、语句超时 5 秒,应用关闭时释放。GET /health 只证明 HTTP 进程可用,GET /health/ready 检查数据库连通性;七牛待接入。

2. 请求处理

  • 全部控制器使用 /api/v1 前缀,公开健康检查为 GET /api/v1/health。
  • 创建 Nest 应用时设置 bodyParser: false,再显式安装 JSON 和 urlencoded 解析器;共同使用字节限制,urlencoded 使用 extended=false。
  • requestId 在解析请求体之前生成;符合 [A-Za-z0-9_-]{8,128} 的 X-Request-Id 可沿用,否则生成 req_UUID。所有响应携带 X-Request-Id。
  • 请求完成记录 method、path、状态、耗时及 requestId,不记录 query、请求体、Authorization、Cookie。JSON 日志递归脱敏密码、token、微信身份及其他敏感字段。
  • Helmet 安全头与隐藏 X-Powered-By。Swagger 开启时放宽文档所需 CSP;Swagger 关闭时使用默认 CSP。
  • CORS 使用精确 origin 白名单,无 Cookie 凭证模式;允许 Bearer Authorization,并向浏览器暴露 X-Request-Id。无 origin 的小程序/服务端请求可用,CORS 不代替身份校验。
  • DTO 使用 ValidationPipe:transform、whitelist、forbidNonWhitelisted;不隐式把数字字符串转换成数字,不在错误里返回原始对象或值。
  • 错误统一为 {code: HTTP状态码, message: 安全提示, requestId},保留 HTTP 状态;JSON 格式错误 400、超限 413、未登录 401、无权限 403、未预期错误 500。可信业务错误新增有限 reason,限流错误携带 Retry-After;成功响应沿用 {code:0,message,data},不重复包装健康检查。

3. Swagger

开发默认地址:http://127.0.0.1:8800/api-docs;OpenAPI JSON:/api-docs-json。Swagger 反映实际注册路由,不展示计划中尚未实现的业务接口。

使用 access-token Bearer JWT 安全定义,健康检查声明为公开。Swagger 不持久保存浏览器 token。生产默认关闭;如部署时显式开启,应通过部署入口限制访问。Swagger 是直接注册的文档路由,不由控制器 JWT 守卫保护。

4. JWT 与账户检查

JwtTokenService 仅供可信服务端业务签发 token,没有公开的测试登录或任意用户 token 签发接口。使用 HS256,签发 sub=userId、authVersion、iat、exp,并验证 algorithm、issuer、audience、有效期和身份字段类型。

AccessTokenGuard 为全局守卫,路由默认需要登录。公开接口使用 @Public(),业务代码用 @CurrentUser() 获取已核对的身份;管理接口使用 @Roles('admin'),角色从当前账户取得,不读取客户端或 token 自报角色。

验签后通过 ACCOUNT_READER 查询账户,要求用户存在、active、userId 一致且 authVersion 匹配。已注销、禁用或版本失效返回 401;不满足角色返回 403。数据库查询失败不降级为“JWT 有效即可通过”。

ACCOUNT_READER 现已接入真实 Prisma 查询;数据库失败返回 503/DATABASE_UNAVAILABLE,不降级放行。POST /auth/wechat/login 接入微信 code2Session、start/resume、唯一冲突处理及行锁;GET /me 返回本人摘要。资料修改、注销及其他业务 API 待实现。测试中的账户读取替身、微信 HTTP 替身和 probe 路由只在测试中使用。

5. 验证

使用 pnpm check 验证格式、ESLint、类型、构建与测试。集成测试覆盖健康检查、前缀、Swagger 开关与 Bearer 定义、CORS、安全头、requestId、JSON/urlencoded、超限和 DTO 校验、日志脱敏、JWT 伪造/过期/错误签名及 claims、账户禁用/缺失/版本失效、服务端角色校验和数据库不可用时的拒绝放行。

2026-10-13:pnpm check 全部通过,12 项测试通过。另使用构建后的 dist/main.js 启动真实进程,核对服务端 .env 加载、健康检查 HTTP 200、OpenAPI JSON HTTP 200 和 X-Request-Id;检查进程已关闭,未修改开发数据库或云服务器。

2026-10-15:接入微信静默登录与真实账户读取后,pnpm check 的 20 项常规测试和独立 pnpm test:db 的 8 项检查通过;构建产物真实启动/数据库连接通过。详细边界与记录见 服务端登录接入说明。

基于 NestJS Swagger 文档 的运行时文档生成方式及 ValidationPipe 文档 的 DTO 校验机制实现;依赖锁定兼容当前 NestJS 11 的具体版本。