fix: NPM 代理配置 block_exploits=false + WebSocket Support (§7)

This commit is contained in:
yourname
2026-04-07 12:27:32 +00:00
parent 60bb25b366
commit 53edbac9cf
2 changed files with 251 additions and 1 deletions

View File

@@ -77,7 +77,11 @@
Admin: http://admin-custom-{project-slug}.dev.d8d.fun → 127.0.0.1:3002
Mini-H5: http://mini-custom-{project-slug}.dev.d8d.fun → 127.0.0.1:5173
```
- 缺失的域名通过 `create_proxy_host` 创建(SSL 由 K8S ingress 处理,不需要在 NPM 中配置
- 缺失的域名通过 `create_proxy_host` 创建(⛔ 参数要求见 `reference/platform-nextjs.md` §7 或 `reference/platform-uni-app.md`
- `block_exploits: false`(默认 true 阻断 WebSocket
- 创建后 `update_proxy_host` 启用 WebSocket Support
- SSL 由 K8S ingress 处理,不需要在 NPM 中配置
- 创建后验证:`get_proxy_host` 确认 `block_exploits: false` 且 `allow_websocket_upgrade: true`
- 将外网域名写入 `pipeline-context.md` 的"外网域名"部分
- **E2E 测试优先使用外网域名**localhost 作为最后 fallback
@@ -226,6 +230,20 @@
- 不一致时以 `pipeline-state.yaml` 为准,同步更新 `sprint-status.yaml`
- 同步后输出一行:`📋 状态同步pipeline-state X done ↔ sprint-status Y done`
7.5. **平台检测与自动配置(⛔ 强制)**
- 检测项目类型,加载对应平台方案集:
```bash
# 检测 Next.js 项目
[ -f "next.config.ts" ] || [ -f "next.config.js" ] && echo "PLATFORM=nextjs"
# 检测 uni-app 项目
[ -f "app/mini-program/src/pages.json" ] && echo "PLATFORM=uniapp"
```
- **Next.js 平台**:按 `./reference/platform-nextjs.md` 逐项检测
- NextAuth trustHost 配置(第 1 节)
- Prisma 7 adapter 配置(第 2 节)
- 检测不通过 → 自动修复并记录到 `pipeline-context.md` 修复记录
- **uni-app 平台**:按 `./reference/platform-uni-app.md` 逐项检测(已有流程不变)
---

View File

@@ -0,0 +1,232 @@
# Next.js 平台方案集
> **⛔ 主流程文件统一引用此文件**:所有 Next.js 平台特定内容集中于此。
> 主流程文件中不再内联平台特定方案,改为引用本文件对应章节。
---
## 1. 外网域名认证(⛔ 强制)
### 问题描述
NextAuth v5 (5.0.0-beta.x) 默认使用 `AUTH_URL` 环境变量的固定值作为 cookie domain 和重定向 URL。
当通过外网域名(如 `api-custom-xxx.dev.d8d.fun`访问时NextAuth 生成的 cookie domain 与请求域名不匹配,
导致浏览器拒绝发送 cookie认证失败。
**症状**
- 外网域名登录后立即跳回登录页cookie 未保存)
- API 测试返回 401 Unauthorized
- localhost 登录正常,外网域名登录失败
### 检测命令
```bash
# 检查 NextAuth 配置是否有 trustHost
grep -q "trustHost" src/lib/auth.ts && echo "PASS: trustHost 已配置" || echo "FAIL: 缺少 trustHost"
# 检查环境变量
grep -q "AUTH_TRUST_HOST" .env && echo "PASS: AUTH_TRUST_HOST 已设置" || echo "WARN: 建议添加 AUTH_TRUST_HOST=true"
```
### 自动修复
在 NextAuth 配置对象顶部添加 `trustHost: true`
```typescript
// src/lib/auth.ts
export const { handlers, auth, signIn, signOut } = NextAuth({
trustHost: true, // ← 关键:让 NextAuth 使用请求的 host 动态推导 URL
providers: [
Credentials({ ... })
],
// ...
});
```
同时在 `.env` 中添加(双重保险):
```
AUTH_TRUST_HOST=true
```
### E2E 测试 Auth 策略
- **外网域名 E2E 测试**:使用 Playwright 浏览器登录trustHost=true 后正常工作)
- **API 测试**curl + cookie jar 方式(先获取 CSRF token再 POST 登录)
- **禁止硬编码 localhost 做 E2E 测试**,应从 `pipeline-context.md` 读取 URL
---
## 2. Prisma 7 配置(⛔ 强制)
### 问题描述
Prisma 7 使用 `@prisma/adapter-pg` driver adapterPrismaClient 需要 `adapter` 参数。
`prisma generate` 的输出路径为 `src/generated/prisma/client`(非 `src/generated/prisma`)。
### 检测命令
```bash
# 检查 Prisma adapter 是否已配置
grep -q "@prisma/adapter-pg" src/lib/prisma.ts && echo "PASS" || echo "FAIL: 缺少 adapter-pg"
```
### 已知问题与修复
1. **seed.ts 编译错误**`prisma/seed.ts` 不应参与 `next build`
- 修复:在 `tsconfig.json``exclude` 数组中添加 `"prisma/seed.ts"`
2. **import 路径错误**
-`import { PrismaClient } from '../src/generated/prisma'`
-`import { PrismaClient } from '../src/generated/prisma/client'`
3. **PrismaClient 初始化**
```typescript
import { PrismaClient } from '@/generated/prisma/client'
import { PrismaPg } from '@prisma/adapter-pg'
const adapter = new PrismaPg({ connectionString: process.env.DATABASE_URL! })
const prisma = new PrismaClient({ adapter })
```
---
## 3. NextAuth v5 类型问题
### 问题描述
next-auth v5 beta 的 `session.user` 类型不完整,直接添加自定义属性(如 id、role会报 TypeScript 错误:
```
Conversion of type 'AdapterUser & User' to type '{ role: string }' is not possible
```
### 修复模式
在 callbacks 中使用 `as any` 类型断言 + eslint-disable 注释:
```typescript
callbacks: {
async session({ session, token }) {
if (session.user) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(session.user as any).id = token.id as string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(session.user as any).role = token.role as string;
}
return session;
},
},
```
---
## 4. Playwright + React 兼容性
### 4.1 React 表单填写
**问题**Playwright 的 `fill()` 方法在 React 18+ 应用中可能不触发 `onChange` 事件,
导致 React state 不更新,表单提交时值为空。
**修复**:使用 `nativeInputValueSetter` 设置值并手动派发事件:
```javascript
await page.evaluate(() => {
const el = document.querySelector('input[type="email"]');
const nativeSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype, 'value'
).set;
nativeSetter.call(el, 'test@example.com');
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
});
```
### 4.2 React 隐藏文件输入
**问题**:隐藏的 `<input type="file">` 在 React 中,`setInputFiles` 不会触发 `onChange` 事件,
导致上传流程无法启动。
**建议**
- 优先通过 API (curl) 验证上传功能
- E2E 测试时通过 `browser_run_code` 触发可见的 UI 元素而非直接操作隐藏 input
---
## 5. 单 Next.js 应用模式
### 适用场景
本项目中 API 后端和前端共用一个 Next.js 应用,与 pipeline 默认的多应用模式不同。
### 关键差异
| 项目 | 多应用模式 | 单应用模式(本项目) |
|------|-----------|-------------------|
| API | `api/` 子目录 | `src/app/api/` 路由 |
| 前端 | `app/admin/` 子目录 | `src/app/` 页面 |
| 端口 | 3001 (API) + 3002 (Admin) | 3001 (单一端口) |
| 环境变量 | 需注入跨域 API URL | 无需注入(同源) |
| pm2 进程 | api + admin | vividspark (单进程) |
### pipeline-context.md 调整
```
## 前端环境变量注入状态
- 无需注入(单 Next.js 应用API 和前端同源)
```
---
## 6. 中间件middleware.ts
### 已知警告
Next.js 16 中 "middleware" file convention is deprecated应使用 "proxy"。
但目前仍可工作,属于 warning 级别,不影响功能。
### middleware 中的 Auth 检查
在 Edge Runtime 中不能使用完整的 `auth()` 函数,应使用 `getToken()` 进行 JWT-only 检查:
```typescript
import { getToken } from "next-auth/jwt"
import { NextResponse } from "next/server"
export async function middleware(request) {
const token = await getToken({ req: request })
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
```
### 需要公开的路由
确保以下路由在 middleware 中被排除:
- `/api/auth/*` — NextAuth 默认路由CSRF、session、callback
- `/login` — 登录页
- `/register` — 注册页
- `/_next/*` — Next.js 静态资源
---
## 7. NPM 代理主机配置(⛔ 强制)
### 问题描述
`next dev` 的 HMR热模块替换依赖 WebSocket 连接。
NPM 代理主机默认配置会阻断 WebSocket导致
- 浏览器控制台持续 `WebSocket connection to 'ws://.../_next/webpack-hmr' failed`
- 页面反复重载React 状态丢失
- Playwright E2E 测试中表单值丢失
### 修复
`create_proxy_host` 创建代理主机时 ⛔ 必须设置:
- `block_exploits: false`(默认 true 会阻断 WebSocket 握手)
- 创建后通过 `update_proxy_host` 启用 WebSocket Support 开关
### 验证
`get_proxy_host` 确认:`block_exploits: false` + `allow_websocket_upgrade: true`