工程化思维驱动AI编程:从零构建Koa2登录系统的对话实践 📅 2026/8/14 3:20:56 1. 从聊天到代码一次工程化思维的对话实践最近在尝试用 Cursor 这个 IDE 来辅助开发它集成的 AI 对话能力确实让人眼前一亮。但和很多开发者一样我最初也陷入了“问一句改一行”的碎片化循环里。直到我把 Harness 那套强调可靠性、可观测性和自动化的工程化思维带进对话整个开发体验才发生了质变。这次我决定用这个思路纯粹通过聊天从零构建一个 Koa2 的用户登录系统。这不仅仅是一次工具使用体验更是一次关于如何将系统性工程思维注入到 AI 辅助编程中的深度实践。你会发现当对话有了“蓝图”和“护栏”AI 就不再是一个随机的代码补全工具而是一个真正理解你架构意图的协作伙伴。整个项目的目标很明确构建一个具备用户注册、登录、JWT 令牌签发与验证、基础权限控制的 Koa2 RESTful API。但核心挑战在于如何通过结构化的对话引导 AI 生成符合生产级要求的代码而不仅仅是能跑通的玩具。这需要我们在对话之初就植入工程化的考量目录结构如何设计才清晰错误处理怎样才算健壮配置管理如何做到环境隔离日志和监控点应该埋在哪里把这些问题的答案变成给 AI 的清晰“指令”就是本次实践的精髓。2. 工程化对话的起点定义清晰的需求与架构蓝图在打开 Cursor 的 Chat 面板之前最重要的一步不是敲代码而是写文档——哪怕只是给自己看的思维导图。工程化思维的核心是“定义先行”。对于登录系统我们需要拆解出非功能性需求NFRs和功能性需求并将它们转化为 AI 能理解的约束条件。2.1 非功能性需求为代码设定质量护栏首先我跟 Cursor 明确了这次项目必须遵守的几条“军规”这些是生成任何代码片段的前提安全性密码必须加盐哈希存储使用bcrypt绝不允许明文。JWT 令牌必须设置合理的过期时间并且提供刷新机制。所有用户输入必须经过验证和清理防止注入攻击。可维护性采用分层架构。至少需要分离出路由层/routes、控制器层/controllers、服务层/services和数据访问层/models或/repositories。这样对话时我可以明确指定“现在请为AuthService编写用户注册逻辑”AI 能准确理解上下文。可观测性关键操作如登录失败、用户注册必须打日志。我要求使用winston或pino这类结构化日志库而不是console.log。这需要在项目初期就引入并配置好日志中间件。配置化数据库连接字符串、JWT 密钥等敏感信息必须通过环境变量使用dotenv管理并区分开发、测试、生产环境。这要求 AI 生成的代码中读取配置的部分是抽象的不能写死。错误处理需要统一的错误处理中间件。业务逻辑中抛出的自定义错误如UserNotFoundError、InvalidCredentialsError应该能被该中间件捕获并返回结构化的、友好的 HTTP 错误响应。把这些要求一次性抛给 Cursor它的理解程度会远超你的预期。你可以这样开始对话“我们将构建一个 Koa2 登录系统。请遵循以下工程规范1. 使用分层架构路由、控制器、服务、模型。2. 密码用 bcrypt 哈希处理。3. 使用 JWT 进行身份验证并需实现令牌刷新。4. 使用环境变量管理配置。5. 实现一个中央错误处理中间件。请首先为我规划一个符合这些规范的项目目录结构。”2.2 功能性需求拆解与 API 设计有了护栏接下来是设计功能蓝图。我和 Cursor 以“产品经理-架构师”协作的方式敲定了核心 API 端点POST /api/auth/register用户注册。需要验证邮箱格式、密码强度并确保邮箱唯一。POST /api/auth/login用户登录。验证凭证成功后签发访问令牌Access Token和刷新令牌Refresh Token。POST /api/auth/refresh使用刷新令牌获取新的访问令牌。POST /api/auth/logout使令牌失效客户端删除即可服务端可选实现令牌黑名单。GET /api/profile受保护端点需要有效的访问令牌才能访问返回用户基本信息。这个设计过程本身也是对话的一部分。你可以问 Cursor“基于 RESTful 原则设计一个包含注册、登录、刷新令牌和获取个人资料的 API 集合并说明每个端点的请求体、响应体和可能的错误码。” AI 会给你一个不错的草案你可以在此基础上进行修正和补充形成最终的 API 契约。这份契约将成为后续所有代码生成的“需求说明书”。3. 与 Agent 的深度协作逐层构建应用骨架有了清晰的蓝图就可以开始指挥 Cursor 这位“智能 Agent”动工了。关键在于每次指令都要有明确的上下文和目标并且要符合我们事先定义的分层架构。3.1 初始化项目与核心依赖安装第一步是创建项目骨架。我并没有手动执行npm init而是直接告诉 Cursor“基于上述架构初始化一个 Koa2 项目。创建基本的目录结构并生成package.json文件安装以下依赖koa,koa-router,koa-bodyparser,dotenv,jsonwebtoken,bcryptjs,winston,joi用于数据验证。同时安装nodemon作为开发依赖。”Cursor 很快就能生成一份结构清晰的package.json和对应的目录。这里的一个经验是你可以要求它使用更现代的替代库比如用koa-body替代koa-bodyparser用zod替代joi。这体现了你作为工程师的技术选型决策而 AI 负责执行。3.2 构建配置管理与日志模块在写业务代码前先搭建好基础设施。这是工程化思维的关键一步。配置管理我指示 Cursor“在项目根目录创建.env.example和.env文件。.env.example中列出所有需要的环境变量如PORT、DB_CONNECTION_STRING、JWT_SECRET、JWT_REFRESH_SECRET、NODE_ENV。然后创建一个config/index.js模块使用dotenv加载配置并导出一个配置对象在不同环境developmentproduction下可以有不同的默认值。”日志模块接着要求它“创建utils/logger.js。使用winston配置一个日志器。要求1. 控制台输出带颜色和时间戳。2. 生产环境将error级别以上的日志写入logs/error.log文件。3. 日志格式为 JSON便于后续收集分析。” AI 生成的配置通常很标准你只需要检查一下日志轮转如使用winston-daily-rotate-file等高级需求是否需要补充。3.3 实现数据模型与数据库连接由于是示例我选择 SQLite 作为数据库方便快捷。我告诉 Cursor“我们将使用knex.js作为 SQL 查询构建器配合sqlite3驱动。请先安装这些依赖。然后创建db/knex.js文件来配置和导出 knex 实例。接着在db/migrations目录下创建一个迁移文件用于创建users表。表字段至少包括id(主键)email(唯一索引)usernamepassword_hashcreated_atupdated_at。”这里可以展示深度协作AI 生成迁移文件后你可以追问“请为这个迁移文件编写一个对应的seeds种子文件插入一个测试用户密码是 ‘password123’ 的 bcrypt 哈希值。” 然后再让它“根据users表结构在models/目录下创建一个User.js模型类提供基础的 CRUD 静态方法如findByEmailcreate。” 通过这一连串有上下文的指令AI 能构建出一个完整的数据访问层雏形。3.4 打造健壮的错误处理与中间件这是让应用从“脆弱”走向“健壮”的核心。自定义错误类我让 Cursor 在utils/errors目录下创建一系列自定义错误类如ApplicationError基类、ValidationError、AuthenticationError、NotFoundError。每个类都有对应的 HTTP 状态码和消息。这能让业务逻辑中的错误抛出更具语义。全局错误处理中间件接下来是关键指令“在middlewares/目录下创建一个errorHandler.js。这个 Koa 中间件需要捕获所有下游中间件抛出的错误。如果是我们自定义的ApplicationError则以其自带的statusCode和message返回 JSON 响应。如果是未知错误如数据库连接失败则在生产环境下返回通用错误信息在开发环境下返回堆栈跟踪同时使用我们之前配置的logger记录error级别日志。”JWT 验证中间件最后让它创建middlewares/auth.js包含一个authenticateJWT函数。这个中间件会从Authorization头中提取令牌用jsonwebtoken验证并将解码后的用户信息如userId挂载到ctx.state.user上供后续路由使用。如果令牌无效或过期则抛出AuthenticationError。4. 业务逻辑实现在对话中注入设计模式基础设施就绪终于可以进入激动人心的业务逻辑编写阶段。通过对话我们可以自然地引入一些设计模式提升代码质量。4.1 实现服务层AuthService 的核心逻辑我直接要求 Cursor“现在请在services/目录下创建AuthService.js。这个类应该包含以下异步方法register(userData)接收邮箱、密码等。验证邮箱唯一性使用bcrypt哈希密码然后通过User模型创建用户。如果邮箱已存在抛出ValidationError。login(email, password)根据邮箱查找用户用bcrypt.compare验证密码。如果成功使用jsonwebtoken生成一个短期访问令牌例如15分钟过期和一个长期刷新令牌例如7天过期并返回它们。如果失败抛出AuthenticationError。refreshToken(refreshToken)验证传入的刷新令牌是否有效且未过期。如果有效解码出用户ID生成一个新的访问令牌返回。 请确保所有方法都进行了适当的错误处理并使用logger记录关键事件如‘用户注册成功’‘登录失败’。”在这个环节你可以和 AI 进行细节讨论。例如当它生成login方法时你可能会问“当前的实现是将刷新令牌直接返回给客户端。考虑到安全最佳实践是否应该将刷新令牌以 HttpOnly Cookie 的方式发送请修改login和refreshToken方法的实现采用 Cookie 方案并说明这样做的利弊。” AI 会修改代码并给出解释利在于可以防止 XSS 攻击窃取令牌弊在于需要处理跨域 Cookie 问题。这种互动正是“聊着天”实现复杂逻辑的体现。4.2 构建控制器与路由服务层完成后控制器和路由就是简单的粘合层。控制器“基于AuthService在controllers/目录下创建AuthController.js。它包含registerloginrefreshlogout等方法。每个方法作为 Koa 中间件从ctx.request.body提取参数调用对应的AuthService方法处理成功或异常并设置ctx.body和ctx.status。记住控制器本身不包含业务逻辑只负责 HTTP 请求/响应的转换。”路由“最后在routes/目录下创建auth.routes.js。使用koa-router定义路由将端点映射到AuthController的方法上。对于/api/profile端点创建一个新的ProfileController和对应的路由并使用authenticateJWT中间件进行保护。”5. 组装、测试与迭代对话驱动的开发闭环所有部件准备完毕现在需要组装并测试。这个过程同样可以通过对话来完成。5.1 应用入口文件与中间件装配我给 Cursor 最终的组装指令“创建app.js作为主应用文件。按顺序完成以下操作1. 加载环境配置。2. 初始化 Koa 实例。3. 使用koa-body中间件解析请求体。4. 使用我们自定义的errorHandler中间件。5. 初始化日志器。6. 连接数据库调用 knex 的初始化。7. 注册所有路由。8. 启动服务器监听配置的端口。”AI 会生成一个结构清晰、中间件顺序正确的app.js。顺序很重要比如错误处理中间件通常需要放在所有其他中间件之前以确保能捕获所有错误。5.2 基于对话的 API 测试我不会直接去写完整的测试套件而是通过对话让 Cursor 帮我生成关键的测试用例和测试命令。“现在请为我编写一个cURL命令用于测试用户注册接口POST /api/auth/register请求体包含emailpasswordusername。” AI 会给出类似curl -X POST http://localhost:3000/api/auth/register -H Content-Type: application/json -d {email:testexample.com,password:yourPassword,username:test}的命令。接着你可以让它“基于刚才成功的注册再生成一个登录的cURL命令并解释如何从响应中提取access_token并在后续请求的Authorization头中使用它。” 更进一步你可以要求“使用jest和supertest为AuthService的login方法编写一个单元测试模拟用户存在和密码正确的情况。” AI 能够生成测试框架和基本的测试用例你只需要填充一些模拟mock逻辑。5.3 工程化思维的后期优化点在基本功能跑通后工程化思维会引导我们思考优化。你可以继续向 Cursor 提问将对话引入更深层次“如何给 JWT 令牌加入黑名单机制以实现更安全的登出”AI 可能会建议使用 Redis 来存储已失效但未过期的令牌 ID。“当前的错误日志是写在文件里的如何集成 Sentry 这样的应用监控平台”它会指导你安装sentry/node包并在错误处理中间件中集成 Sentry 的捕获调用。“如何编写一个docker-compose.yml文件将本应用和它依赖的 PostgreSQL 数据库容器化”AI 能生成一个标准的 Dockerfile 和 docker-compose 配置。通过这一系列从宏观到微观、从架构到细节的对话你不仅得到了一个可运行的 Koa2 登录系统更完成了一次完整的、基于工程化思维的 AI 辅助开发流程演练。最终你会发现核心产出物不仅仅是代码更是一套可复用的、与 AI 高效协作的“对话模式”。这套模式强调规划先行、关注非功能性需求、分层实施和持续验证它能确保 AI 生成的代码从一开始就走在正确的轨道上极大提升开发效率和代码质量。下次当你打开 Cursor 或任何 AI 编程工具时不妨先花几分钟用工程化的思维为你们的对话画一张“蓝图”。