用Claude Code构建商业级网站:从JWT鉴权到CI/CD自动化部署 📅 发布时间:2026/9/4 15:52:56 👁 浏览次数: 很多团队在接触 Claude Code 时第一反应是“让它帮我写个网站”。实际用下来你会发现真正容易翻车的不是“能不能写”而是“怎么让它按工程标准写”目录怎么分层、密钥放哪里、登录态怎么刷新、上传的视频转码后存哪、部署到服务器后 CI 怎么跑。这篇文章就用一条完整的实战主线来拆开讲用 Claude Code 从零搭一个带后端鉴权、数据库、多媒体处理的商业级网站并且配上自动化部署。我会把任务拆成一个真实工程来推进Node.js 后端 MySQL ffmpeg 多媒体处理 JWT 登录鉴权 GitHub Actions 自动部署。为了让 Claude Code 不“自由发挥”每一阶段都会先给出约束条件、再给提示词工作流、最后补验证方式。这样你照着做既能看到 AI 编码的上限也知道哪些环节必须人来兜底。如果你已经装了 Claude Code可以直接跳到工程初始化部分如果还没装先看环境准备。全程不追求把代码堆得花里胡哨重点是把“能用、可维护、可部署”这条链路走通。1. Claude Code 核心能力与项目定位Claude Code 是 Anthropic 推出的命令行 AI 开发代理工具它不是在网页里和你聊代码而是直接进入终端、读取你的工程目录、修改文件、执行命令。也就是说它能基于真实代码库完成任务而不是基于一段上下文猜测代码。能力项说明交互方式终端命令行交互在项目目录内运行工程能力阅读工程结构、定位代码、跨文件修改、调用构建与运行命令项目记忆通过CLAUDE.md约定技术栈、命名规范、业务规则避免每次重新交代安装门槛依赖 Node.js官方提供 npm 安装方式适合任务全栈功能开发、代码重构、数据库脚本、自动化部署配置、测试补全不适合任务未经确认的全局大重构、生产环境直接改库、完全替代人工 Code Review这个项目定位很明确不是让你把 Claude Code 当“自动生成器”用而是把它当“按需求施工的高级工程师”。你负责拆需求、定边界、做审查它负责把接口、数据表、中间件、部署脚本这些琐碎但量大的工作落地。商业级网站意味着三个硬指标第一登录鉴权必须安全不能把用户密码明文存库第二数据库结构必须清晰后续加字段不能牵一发动全身第三部署必须可重复换一台服务器也能自动跑通。这三条正好是 Claude Code 能切入的发力点。2. 商业网站模块划分与交付顺序建议先构建一个“用户上传并管理多媒体资源”的内容平台它同时覆盖了登录鉴权、用户体系、内容管理、文件存储和视频转码。这个模型很典型用户注册、登录、上传图片/视频、查看自己的资源列表、删除资源后台按角色区分普通用户和管理员。模块拆分如下模块核心职责技术选型示例用户认证注册、登录、访问令牌刷新JWT 刷新令牌权限控制区分普通用户与管理员RBAC 或简单角色字段数据库层用户、角色、媒体资源、令牌存储MySQL 8.x对象/文件存储图片、视频文件保存与访问本地磁盘或云存储多媒体处理视频转码、封面抽取、图片压缩ffmpeg ffprobe后端 API暴露登录、资源上传、列表接口Node.js TypeScript Express自动化部署推送代码后自动构建并发布GitHub Actions PM2 Nginx交付顺序建议按“先不稳定后稳定”的依赖链走先搭数据库和连接层再做用户注册登录然后做鉴权中间件再写多媒体上传与转码最后接自动化部署。这样前一步的产物是后一步的输入验证路径最短。让 Claude Code 干活前必须先把技术栈和目录结构定死。最好的办法不是口头描述而是直接在仓库里放一个CLAUDE.md。这个文件会被 Claude Code 在会话开始时读取相当于项目的“施工说明书”。3. 本地环境与 Claude Code 安装开始前需要准备以下环境依赖用途检查命令Node.js 18运行 Claude Code 与后端服务node -vnpm安装 Claude Code CLInpm -vGit管理代码变更git --versionMySQL 8.x后端数据库mysql --versionffmpeg/ffprobe视频转码与信息探测ffmpeg -versionClaude CodeAI 编程代理claude --version安装 Claude Code 使用官方 npm 方式npm install -g anthropic-ai/claude-code claude --version安装完成后你需要有可用的认证凭据通常是通过ANTHROPIC_API_KEY环境变量指定 API 密钥或者在首次启动时按工具引导完成登录。export ANTHROPIC_API_KEY你的密钥需要留意的是这类编程代理会直接调用你的终端命令因此建议在独立项目目录里运行而不是在系统根目录或包含敏感文件的目录里随意使用。ffmpeg 在不同操作系统下的安装方式不同但装完后一定要验证两个命令都存在因为后端的视频转码和封面生成依赖它们ffmpeg -version ffprobe -version终端没问题后进入工作目录执行claude即可进入交互模式。启动后Claude Code 会扫描当前工作目录如果项目刚初始化它需要你对整体规划给出清晰指令。4. 从零初始化工程给 Claude Code 一份可执行的施工说明很多项目翻车不是因为 AI 能力不够而是第一步就给了一个过于宽泛的指令“帮我做个网站”。正确做法是把目标拆成具体工程约束再让 Claude Code 执行。先手动创建项目根目录并初始化 Gitmkdir commerce-site cd commerce-site git init在启动 Claude Code 前先把项目结构说明写进CLAUDE.md。这个文件不用很长但必须写清楚技术栈、目录约定、命名规范、禁止事项。然后启动claude在会话里给出第一阶段指令注意这里不要让它一口气写完整站我需要你帮我在当前目录下初始化一个全栈项目 1. 后端使用 Node.js TypeScript Express。 2. 使用 MySQL 作为数据库禁止直接使用 SQL 文件初始化必须提供可重复执行的数据库迁移脚本。 3. 环境变量统一从 .env 读取禁止把密钥硬编码到源码里。 4. 先搭建工程骨架src/index.ts、src/config、src/routes、src/controllers、src/services、src/middlewares、migrations 目录。 5. 先不要写业务接口完成目录结构和依赖安装即可。这一步的目的不是让 Claude Code 生成完整业务代码而是先建立工程骨架。生成结果可以人工检查文件结构是否符合预期。建议的单仓库结构如下commerce-site/ ├── CLAUDE.md ├── .env.example ├── .gitignore ├── package.json ├── src/ │ ├── index.ts │ ├── config/ │ │ └── env.ts │ ├── middleware/ │ │ ├── auth.ts │ │ └── error.ts │ ├── routes/ │ │ ├── auth.ts │ │ ├── media.ts │ │ └── user.ts │ ├── service/ │ │ ├── auth.service.ts │ │ └── media.service.ts │ └── db/ │ └── pool.ts ├── migrations/ └── scripts/ └── deploy.sh骨架确认没问题后让 Claude Code 在内存中形成“项目文档”后续每一步都拿这个结构约束它。注意AI 生成的代码不一定符合你团队规范所以骨架阶段一定要看关键文件的实际内容特别是package.json和.env.example。5. 后端鉴权从建表到 JWT 路由守卫后端鉴权是商业级网站最核心的一条链路。用户注册、登录、访问令牌刷新、角色权限控制任何一个环节松懈都可能导致越权或数据泄露。5.1 数据库表结构设计建议让 Claude Code 先设计用户基础表和角色表并让它把“不存明文密码”写成表字段约束。下面是一组参考 DDLCREATE TABLE users ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, email VARCHAR(190) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, nickname VARCHAR(60) NOT NULL DEFAULT , role ENUM(user, admin) NOT NULL DEFAULT user, status TINYINT NOT NULL DEFAULT 1 COMMENT 1正常 0禁用, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;用户登录后如果使用 JWT短期令牌通常不需要落库但如果你需要支持主动踢人、续期可以在表里加一个会话或刷新令牌表。5.2 注册登录逻辑与安全要求向 Claude Code 提出需求时至少包含下面几点密码不能存储明文使用 bcrypt 或 argon2 哈希。登录成功后返回 access token有效期通常 30 到 120 分钟。access token 过期后通过 refresh token 换取新 token。登录失败次数过多时返回统一的“邮箱或密码错误”不暴露用户是否存在。下面的 Node.js 注册服务代码展示了哈希和用户创建的核心流程可以让 Claude Code 基于这个思路生成完整实现import argon2 from argon2; import { getPool } from ../db/pool; export async function register(email: string, password: string, nickname: string) { if (!email || !password || password.length 8) { throw new Error(INVALID_PARAM); } const pool getPool(); const passwordHash await argon2.hash(password, { type: argon2.argon2id, memoryCost: 19456, timeCost: 2, parallelism: 1, }); const [result] await pool.execute( INSERT INTO users (email, password_hash, nickname, role) VALUES (?, ?, ?, user), [email, passwordHash, nickname] ); return (result as any).insertId; }这段代码只是骨架真实实现还需要处理邮箱已被注册时的去重错误建议让 Claude Code 补上ER_DUP_ENTRY错误捕获并返回友好的中文提示。5.3 JWT 鉴权中间件与角色守卫登录完成后需要保护/api/media这类业务接口。推荐把鉴权逻辑放在一个中间件里注册后统一应用到需要登录的路由。可以给 Claude Code 下发如下任务在 src/middleware/auth.ts 里 1. 读取 Authorization 请求头解析 Bearer Token。 2. 使用 JWT 密钥校验 tokentoken 解析失败时返回 401。 3. 校验通过后把 userId 和 role 写入 req供后续控制器使用。 然后新增 requireAdmin 中间件当当前用户不是 admin 时返回 403。下面是常见的 JWT 鉴权中间件实现import type { Request, Response, NextFunction } from express; import jwt from jsonwebtoken; const JWT_SECRET process.env.JWT_SECRET || ; interface JwtPayload { sub: number; role: string; } export function requireAuth(req: Request, res: Response, next: NextFunction) { const header req.headers.authorization || ; const token header.startsWith(Bearer ) ? header.slice(7) : ; if (!token) { res.status(401).json({ code: 401, message: 缺少访问令牌 }); return; } try { const payload jwt.verify(token, JWT_SECRET) as JwtPayload; req.userId payload.sub; req.role payload.role; next(); } catch { res.status(401).json({ code: 401, message: 令牌无效或已过期 }); } } export function requireAdmin(req: Request, res: Response, next: NextFunction) { if ((req as any).role ! admin) { res.status(403).json({ code: 403, message: 没有管理员权限 }); return; } next(); }模型里强调一点JWT_SECRET绝不能写死在源码中必须通过环境变量注入且生产环境要使用足够长的随机字符串。可以让 Claude Code 生成一个.env.example文件把密钥明文替换成占位符。5.4 接口验证鉴权模块写完先用本地服务验证链路。启动 API 服务后用 curl 模拟注册、登录、访问受保护资源三步curl -X POST http://127.0.0.1:8080/api/auth/register \ -H Content-Type: application/json \ -d {email:userexample.com,password:12345678,nickname:测试用户}curl -X POST http://127.0.0.1:8080/api/auth/login \ -H Content-Type: application/json \ -d {email:userexample.com,password:12345678}登录成功后会返回类似下面的结构{ accessToken: 一串JWT, refreshToken: 一串refresh token, expiresIn: 7200 }拿着 access token 去访问受保护接口curl http://127.0.0.1:8080/api/user/me \ -H Authorization: Bearer 刚才返回的accessToken一个可靠的鉴权链路至少满足三条没有 token 返回 401错误 token 返回 401admin 接口用普通用户 token 应返回 403。如果这三条都不满足说明中间件没挂对或 token 解析逻辑有问题。6. 数据库事务与多媒体处理6.1 用迁移脚本管理数据库变更正式项目中不建议用CREATE TABLE一遍遍手写建表最好让 Claude Code 生成可重复执行的迁移脚本。迁移脚本的本质是记录数据库的每一次结构变更并按序号执行。如果后续要加字段只需要新增一个迁移文件而不是修改旧的 DDL。# 迁移文件目录 migrations/ ├── 001_init.sql ├── 002_add_media_table.sql以媒体表为例一个常见的 DDL 如下CREATE TABLE medias ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(20) NOT NULL COMMENT image/video, storage_path VARCHAR(500) NOT NULL, mime_type VARCHAR(100) NOT NULL DEFAULT , size_bytes BIGINT UNSIGNED NOT NULL DEFAULT 0, width INT UNSIGNED DEFAULT NULL, height INT UNSIGNED DEFAULT NULL, duration_seconds DECIMAL(10,3) DEFAULT NULL, cover_path VARCHAR(500) DEFAULT NULL, status TINYINT NOT NULL DEFAULT 1 COMMENT 1处理中 2成功 3失败, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX idx_user (user_id), CONSTRAINT fk_media_user FOREIGN KEY (user_id) REFERENCES users(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;向 Claude Code 提出需求时要明确“禁止在生产环境直接改表结构”让数据库变更全部走迁移脚本。这个约定能避免项目后期结构混乱。6.2 事务与用户资源一致性上传多媒体资源时通常有两个写操作插入媒体记录、更新用户的媒体数量统计。这种场景必须使用事务保证两个操作要么同时成功、要么同时失败。import { getConnection } from ../db/pool; export async function createMediaRecord(userId: number, meta: MediaMeta) { const conn await getConnection(); try { await conn.beginTransaction(); const [result] await conn.execute( INSERT INTO medias (user_id, name, type, storage_path, mime_type, size_bytes, status) VALUES (?, ?, ?, ?, ?, ?, 1), [userId, meta.name, meta.type, meta.storagePath, meta.mimeType, meta.sizeBytes] ); await conn.execute( UPDATE users SET media_count media_count 1 WHERE id ?, [userId] ); await conn.commit(); return (result as any).insertId; } catch (err) { await conn.rollback(); throw err; } finally { conn.release(); } }注意事务结束后才启动转码任务不要把耗时任务包进事务里否则数据库连接会长时间占用并发一高很容易把连接池打满。6.3 视频上传与 ffmpeg 转码商业级网站的多媒体处理不能只接收文件。建议让 Claude Code 实现以下流程客户端上传原始图片/视频。后端校验文件大小、MIME 类型和后缀名。文件先存储到“待处理目录”。通过 ffprobe 读取视频元数据。通过 ffmpeg 转码为标准 H.264 AAC 的 MP4。生成视频封面。更新数据库中的处理状态。如果是图片可以生成缩略图并压缩避免原图直接暴露。关键命令示例# 读取视频的时长、分辨率、码率信息 ffprobe -v error -show_streams -show_format input.mp4 # 转码成 H.264 AAC ffmpeg -y -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -movflags faststart output.mp4 # 截取第 5 秒作为视频封面 ffmpeg -y -ss 5 -i input.mp4 -frames:v 1 -q:v 4 cover.jpg在 Node.js 中通过子进程调用 ffmpeg 时加一个超时时间是必要的避免转码进程卡死import { execFile } from child_process; import { promisify } from util; const execFileAsync promisify(execFile); export async function transcodeVideo(input: string, output: string) { await execFileAsync( ffmpeg, [ -y, -i, input, -c:v, libx264, -crf, 23, -preset, medium, -c:a, aac, -movflags, faststart, output, ], { timeout: 10 * 60 * 1000 } ); }如果上传量很大不建议在 HTTP 请求内同步执行 ffmpeg而是把任务丢到任务队列里异步处理。项目早期没有 Redis 队列时可以先让 Claude Code 用“数据库表字段标记状态 定时扫描处理”的方式实现一个极简异步任务表。6.4 多媒体处理模块验证验证转码是否成功不要只看返回 200要看数据库里媒体记录有没有从“处理中”变成“成功”并确认生成后的文件确实存在于目标目录。ffprobe -v error -show_entries formatduration,size -of json output.mp4如果输出里没有error信息且 duration 是数值表示转码产物可用。还有一种很隐蔽的问题转码进程“看似成功”但产物是空文件通常是因为磁盘空间不足或 ffmpeg 没有写权限需要重点关注日志里的编码器错误。7. 自动化部署与持续集成7.1 用 GitHub Actions 做 CI 部署自动化部署的关键是让代码合并到主分支后测试、构建、推送服务器全部自动执行。下面是一个 GitHub Actions 工作流示例它在代码推送到 main 分支时触发name: deploy on: push: branches: [ main ] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: 拉取代码 uses: actions/checkoutv4 - name: 安装 Node uses: actions/setup-nodev4 with: node-version: 20 - name: 安装依赖 run: npm ci - name: 执行测试 run: npm run test --if-present - name: 编译项目 run: npm run build - name: 远程部署 uses: appleboy/ssh-actionv1.2.0 with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /var/www/commerce-site git pull origin main npm ci --omitdev npm run build pm2 reload api --update-env使用第三方 action 时要注意它们的版本会更新上例中的版本号需要根据当前可用版本调整。更稳妥的方法是先用 SSH 命令手动部署一次确认服务器上的目录和权限没问题后再接入 CI。7.2 PM2 守护 Node 进程自动化部署后Node 服务不能前台跑在终端里需要使用 PM2 作为进程守护。这里给一个ecosystem.config.js示例module.exports { apps: [ { name: api, script: dist/src/index.js, instances: 1, exec_mode: fork, env: { NODE_ENV: production, }, }, ], };服务器上的部署命令可以手动先跑一遍cd /var/www/commerce-site git pull origin main npm ci --omitdev npm run build pm2 reload api --update-env7.3 Nginx 反向代理与静态资源如果是前后端分离项目前端打包后的静态文件由 Nginx 托管后端 API 通过反向代理转发server { listen 80; server_name your-domain.com; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 50m; } location /uploads/ { alias /var/www/commerce-site/uploads/; expires 7d; } }client_max_body_size大小要根据你的多媒体上传需求设置默认 1m 太小视频上传基本必失败。如果上传超过 Nginx 限制客户端会收到 413 错误这属于配置层问题不是代码问题。7.4 CI 部署验证自动化部署完成后至少验证三条链路访问登录接口能返回 JSON访问受保护接口无 token 时返回 401用测试用户走一遍注册流程确认数据库表有新增记录。如果 CI 里执行了数据库迁移要看是否做了幂等保护否则重复部署时可能会因为重复建表而失败。8. Claude Code 常见问题与排查方法问题现象可能原因排查方式解决方案claude命令不存在npm 全局目录不在 PATH 中检查claude --version重新安装或配置 npm 全局 bin 到 PATHClaude Code 启动后无法登录API 密钥无效或登录凭据配置错误检查环境变量和登录状态按官方引导重新登录或更新 API 密钥第三方模型接入时报模型不识别配置的模型名不被当前版本或 API 网关支持查看启动日志中实际使用的模型标识确认账号权限使用与当前客户端版本匹配的模型标识Claude Code 生成的代码没有遵循项目规范项目根目录缺少CLAUDE.md或新会话未重新读取检查CLAUDE.md是否存在在项目根目录维护清晰的项目说明文件AI 一次改动太多代码难以审查指令范围过大拆分需求一次只完成一个模块按“建表→鉴权→接口→部署”逐个推进登录接口密码错误时报错但不友好数据库异常被直接抛出查看后端日志与响应体增加统一异常处理与错误码ffmpeg 转码失败ffmpeg 未安装或服务器缺少编码器ffmpeg -version检查安装完整 ffmpeg确认 libx264 可用上传大视频时接口超时Nginx 超时或后端同步转码查看 Nginx error.log调大超时时间或改用异步队列处理CI 部署后服务没有更新PM2 未 reload 或远程目录不对登录服务器手动执行命令检查部署脚本的远程路径和 PM2 服务名另一个常见问题是Claude Code 生成的代码“看着能跑”但存在严重的目录越界。例如上传接口允许用户传入自定义路径导致任意文件覆盖。遇到这种问题建议单独让 Claude Code 做一次安全审计并把“禁止拼接用户输入到文件路径”写进CLAUDE.md。9. 安全合规、边界与团队协作建议这套项目里涉及三个敏感面用户账号数据、上传的多媒体内容、部署服务器的访问凭据。商业级系统对这些数据必须有明确边界数据库密码、JWT 密钥、云存储密钥不能进 Git 仓库统一走环境变量或密钥管理服务。用户上传的图片、视频可能包含个人肖像或版权内容上线前必须获得合法授权明确素材的版权归属和使用范围。包含人脸或声音的数据处理功能必须遵守相关法律法规并在产品中向用户说明数据用途。生产环境不允许直接修改数据库所有变更必须经过迁移脚本并在测试库先执行。给普通用户开放的接口要测试越权场景用户 A 能否访问用户 B 的资源。在团队协作层面Claude Code 生成的代码不能直接合并到主分支。建议把它输出当作“高密度代码草稿”每一个关键文件都要过一遍人工 Code Review。重点检查三处鉴权中间件有没有实际挂到路由上文件上传的目录是否可控数据库连接有没有正确释放。如果你在本机同时跑多个环境注意.env文件不一致导致的问题。最容易踩的坑就是本地测试能用推到服务器后因为缺少某个环境变量而崩溃。一个比较稳的实践是把.env.example提交到仓库把真实.env加到.gitignore中部署时由 CI 从仓库 Secrets 注入。最后给出一个可以直接沿用的工作流先让 Claude Code 输出一段需求拆解再由你把拆解结果写进CLAUDE.md之后按数据库、鉴权、业务接口、外部集成、部署配置的顺序每个部分单独开启一次会话每次会话结束后让人工审查关键 diff 并运行一次最小测试。这个循环走通以后你会看到 Claude Code 在标准工程里的产出质量会稳定很多它最擅长的是在清晰边界内快速生成大量可编译的代码而最需要的恰恰是你对边界和验收标准的把控。