2026-03-23 AI Text Humanizer 线上部署 & 安全加固

一、线上环境打通(上午完成)

问题:Humanize 功能线上 500 错误

  • 现象:点击 Humanize 按钮报 Unexpected token 'I', "Internal S"... is not valid JSON
  • 根因:setInterval() 在 Cloudflare Workers 全局作用域不被允许(异步 I/O 限制),模块加载时就报错
  • 修复:删除 setInterval,改成每次请求时 lazy cleanup
  • 结果:✅ 线上功能跑通,AI 检测评分从 80 降到 50

Cloudflare 环境变量配置

  • ZHIPU_API_KEY 已在 production 环境配好
  • 发现 Cloudflare 监听 main 分支,但代码在 master 分支
  • 通过 API 手动触发部署解决了分支不匹配问题
  • 教训:Cloudflare API Token 存在 config/cloudflare-token.json,搜凭证时应直接扫 config 目录

二、安全加固(下午完成)✅

需求:防止直接调用 API 白嫖免费次数

三层防护全部上线:

1. Cloudflare Turnstile(Bot 防护)

  • 在 Cloudflare 控制台创建 Turnstile 实例
  • Site Key:0x4AAAAAACu1U9esqyj_y103
  • Secret Key:通过 Cloudflare Pages 环境变量注入
  • 前端:components/ui/turnstile.tsx,managed 模式,页面加载时自动验证,隐藏组件
  • 后端:lib/turnstile.ts,调用 Cloudflare siteverify API 校验 token
  • 难点:NEXT_PUBLIC_ 变量需要在 build 时嵌入,最终通过 next.config.tsenv 字段解决

2. CORS 白名单

  • lib/cors.ts:只允许 ai-humanizer-b70.pages.dev 和 localhost 开发地址
  • 无 origin/referer 的请求放行(同源直接访问)

3. HMAC 签名验证

  • lib/signature.ts:Web Crypto API 实现 HMAC-SHA256
  • 前端:app/humanize/page.tsx,每次请求生成 timestamp + nonce + HMAC 签名
  • 后端:校验签名 + 时间戳新鲜度(5 分钟窗口)+ nonce 防重放
  • Secret:SIGN_SECRET 环境变量,前后端共享

4. 结构化日志

  • lib/logger.ts:JSON 格式日志,包含 requestId、IP、各阶段(parse/cors/signature/turnstile/rate_limit/provider/success/error)
  • 每个请求有唯一 ID,方便排查问题

API 验证流程

请求 → CORS 检查 → 签名验证 → Turnstile 验证 → 限流检查 → 业务逻辑

部署详情

  • Build:next.config.ts 添加 env.NEXT_PUBLIC_TURNSTILE_SITE_KEY 确保 build 时嵌入
  • 环境变量(Cloudflare Pages):
    • ZHIPU_API_KEY — 智谱 API
    • SIGN_SECRET — HMAC 签名密钥
    • TURNSTILE_SECRET_KEY — Turnstile 后端密钥
  • 最终部署地址:https://ai-humanizer-b70.pages.dev

当前产品状态

  • 线上地址:https://ai-humanizer-b70.pages.dev/humanize ✅ 可用
  • 安全防护:✅ Turnstile + CORS + 签名 三层
  • 日志系统:✅ 结构化 JSON 日志
  • 部署平台:Cloudflare Pages
  • 代码分支:master / main(已同步)
  • 打卡进度:5 次(最后 3/21)

三、Google OAuth 登录(晚间完成)✅

技术方案

  • NextAuth.js v5 (beta.30) + Google Provider
  • JWT Session Strategy:不需要数据库,session 存在 JWT token 里
  • Auth 为可选功能,不强制登录,匿名用户照常可用
  • 全部兼容 Cloudflare Workers Edge Runtime

新增/修改文件

| 文件 | 说明 | |------|------| | app/api/auth/[...nextauth]/route.ts | NextAuth 路由 handler,配置 Google provider + JWT callbacks | | components/auth-provider.tsx | SessionProvider 包裹组件 | | components/user-menu.tsx | 登录后显示用户头像、邮箱、登出按钮 | | components/navbar.tsx | 集成 Sign In 按钮(未登录)+ UserMenu(已登录) | | middleware.ts | NextAuth middleware(edge runtime) | | app/layout.tsx | 包裹 AuthProvider |

遇到的坑

  1. NextAuth v5 废弃了 next-auth/middleware:v5 不再导出 defaultwithAuth,middleware 里无法直接 re-export。最终在 route 里 export GET/POST handler,middleware 用 withAuth 从 auth core 导入
  2. Route handler 类型冲突:Next.js 15 要求 route export 符合 NextRequest → NextResponse 类型,但 NextAuth handler 签名不匹配。用 as any 绕过
  3. Edge Runtime 标记缺失:Cloudflare Pages 要求所有非静态路由导出 export const runtime = 'edge',否则 @cloudflare/next-on-pages 构建失败
  4. Wrangler 缓存问题wrangler pages deploy 默认跳过已上传文件(即使内容变了但文件名相同),导致多次部署看起来成功但线上没变化。需要加 --skip-caching 强制上传全部文件
  5. Production 分支不匹配:项目没有 git 集成(Source: None),所有 wrangler 部署都是 ad_hoc/preview 类型。需要在 Cloudflare Pages Settings 里手动添加环境变量(API 无权限),且部署到 main branch 才能命中 production alias
  6. _next-auth export 类型问题:v5 的 handler 不是标准的 Route handler 类型,需要 cast 到 any 才能通过 Next.js 类型检查

环境变量(Cloudflare Pages)

| 变量 | 用途 | |------|------| | GOOGLE_CLIENT_ID | Google OAuth Client ID | | GOOGLE_CLIENT_SECRET | Google OAuth Client Secret | | NEXTAUTH_SECRET | JWT 签名密钥 | | NEXTAUTH_URL | 回调 URL(https://ai-humanizer-b70.pages.dev) |

Google Cloud Console 配置

  • OAuth Client ID:10551764124-pu94ko93v4te55r0eaf4lg03umr8rd4p.apps.googleusercontent.com
  • Authorized redirect URI:https://ai-humanizer-b70.pages.dev/api/auth/callback/google

用户体验

  • 导航栏右侧:未登录显示 Sign In 按钮 + Get Started 按钮
  • 点击 Sign In → Google OAuth 授权 → 跳回 /humanize
  • 登录后显示用户头像 + 邮箱 + 登出下拉菜单
  • 移动端菜单同样有 Sign In with Google 按钮

四、D1 数据库集成 & NextAuth 修复(2026-03-24)✅

问题:NextAuth 线上 500 错误

  • 现象:3/23 晚上配好的 Google 登录,3/24 早上发现 /api/auth/* 全部 500
  • 根因:Cloudflare Pages 的环境变量被之前的 API 操作覆盖清空了(NEXTAUTH_SECRET 缺失 → MissingSecret 错误)
  • 修复过程
    1. 通过 wrangler pages deployment tail 查看生产日志,确认错误是 MissingSecret
    2. 用 Cloudflare API 一次 PATCH 全部 7 个环境变量(plain_text 类型)
    3. 重新 build + deploy,验证 csrf/signin/home 全部 200
    4. POST /api/auth/signin/google 成功 302 到 Google 授权页
  • 教训:CF Pages API PATCH 是全量替换不是增量更新;生产问题要第一时间看生产日志

D1 数据库绑定

  • 数据库ai-humanizer-db(ID: 8ed3fde1-ce90-4a5c-aa81-ea8bf32bbb16
  • 绑定名DB
  • 已创建的表:users、humanization_history、daily_usage(migration: migrations/0001_init.sql
  • 访问层lib/db.ts,通过 getRequestContext() 获取 D1
  • 验证/api/test-db 确认 DB binding 可用、三张表读写正常
  • wrangler.toml 中配置了 [[d1_databases]] 绑定

用户菜单优化

  • 之前:登录后显示 Google 头像 + 邮箱 + Sign Out 按钮
  • 现在
    • 点击头像展开下拉菜单
    • 显示用户名(从 Google 读取)、邮箱
    • 无头像时显示名字首字母渐变圆形
    • Humanize 页面 header 也统一了登录状态

最终环境变量(Cloudflare Pages Production)

| 变量 | 用途 | |------|------| | GOOGLE_CLIENT_ID | Google OAuth Client ID | | GOOGLE_CLIENT_SECRET | Google OAuth Client Secret | | NEXTAUTH_SECRET | JWT 签名密钥 | | NEXTAUTH_URL | https://ai-humanizer-b70.pages.dev | | ZHIPU_API_KEY | 智谱 AI API Key | | SIGN_SECRET | HMAC 签名密钥 | | TURNSTILE_SECRET_KEY | Cloudflare Turnstile 后端密钥 |

部署踩坑记录

  1. 环境变量被清空:之前用 PATCH 逐个设置变量,每次覆盖其他变量为空
  2. secret_text 类型值不可读:API 返回 success 但实际值可能没写入,改用 plain_text
  3. NODE_ENV 是 reserved binding:不能作为 Pages 环境变量名,会导致 deploy 失败
  4. next build 间歇性失败Collecting build traces 阶段偶尔 ENOENT,重跑即可
  5. 子 agent 干扰:超时的子 agent 进程在后台删 .vercel 目录,导致 deploy 间歇性失败

当前产品状态

  • 线上地址:https://ai-humanizer-b70.pages.dev ✅
  • 安全防护:✅ Turnstile + CORS + 签名 三层
  • Google 登录:✅ NextAuth v5 + Google OAuth(已验证完整流程)
  • D1 数据库:✅ 绑定成功,三张表可读写
  • 用户菜单:✅ 头像 + 用户名 + 下拉菜单
  • 日志系统:✅ 结构化 JSON 日志
  • 部署平台:Cloudflare Pages
  • 代码分支:master

待办

  • [x] ~~Google 登录~~ ✅ 2026-03-23
  • [x] ~~D1 数据库绑定~~ ✅ 2026-03-24
  • [x] ~~用户菜单优化~~ ✅ 2026-03-24
  • [ ] OAuth 回调后自动写入 D1 用户表
  • [ ] 用户 Dashboard
  • [ ] 使用历史记录页面
  • [ ] 绑自定义域名
  • [ ] 邮箱 + 验证码登录(备选方案)
  • [ ] 支付集成(Stripe/PayPal)
  • [ ] SEO 优化(meta tags、og tags、sitemap)
  • [ ] Product Hunt 发布
  • [ ] Reddit/Twitter 推广
  • [ ] 博客内容矩阵