好的,这是一份经过整理和条理化的复盘报告,涵盖了您提供的所有内容。
项目开发复盘报告:题库适配器与平台迁移
本文档旨在系统地复盘“为 tikuAdapter 新增适配端点”任务从初期开发、环境配置、数据兼容性处理,直至最终平台迁移与自动化部署的完整过程。报告详细记录了关键任务、遇到的问题、解决方案及宝贵的经验教训。
I. 核心API端点开发与初期问题解决
1.1 任务目标
创建-一个新的 API 端点 /tikuAdapter,该端点能够接收特定格式请求,调用外部题库 API (api.tikuhai.com),并将返回数据转换为 tikuAdapter 所需的 JSON 格式。
1.2 已完成工作
- 新增
/tikuAdapter端点:在src/app.js中成功添加了路由和handleTikuAdapterSearch处理函数。 - 实现数据格式转换:在
handleTikuAdapterSearch中编写核心逻辑,将api.tikuhai.com的响应重组,包括保留question和options,并动态生成answerKey、answerIndex、answerKeyText和answerText等字段。
1.3 遇到的问题及解决方案
问题一:服务器连接重置
- 现象:
curl测试时收到(56) Recv failure: Connection was reset错误。 - 分析: 服务器处理请求时意外终止或崩溃。
- 解决方案: 检查
request.log日志文件,定位导致崩溃的具体异常。
问题二:处理 options 字段时的类型错误
- 现象: 日志显示
TypeError: Cannot read properties of undefined (reading 'indexOf')。 - 分析: 当客户端请求 JSON 不含
options字段时,options变量为undefined,导致后续调用indexOf失败。 - 解决方案: 增加防御性编程:
const options = data.options || [];,确保options始终为数组,即使请求中未提供。
II. 开发环境配置与效率提升
2.1 原始需求:实现开发环境下的代码热重载
- 目标: 修改后端代码后服务能自动重启,提升开发效率。
- 解决方案: 采用 Node.js v18.11.0+ 内置的
--watch标志。 - 优势: 无需额外依赖(如
nodemon),官方支持,性能更佳。 - 实施: 修改
package.json,添加"dev": "node --watch src/app.js"命令,通过npm run dev启动。
2.2 衍生问题:端口被占用 (EADDRINUSE)
- 现象: 启动开发服务时抛出
Error: listen EADDRINUSE: address already in use :::3000错误。 - 分析: 端口
3000被未正常关闭的原服务进程占用。 - 解决方案:
- 定位进程: 使用
netstat -aon | findstr ":3000"查找占用端口的进程ID (PID)。 - 终止进程: 使用
taskkill /PID [PID] /F强制结束该进程,释放端口。
- 定位进程: 使用
III. 请求数据处理与外部API兼容性增强
3.1 背景
在调试过程中,目标是正确解析前端请求体,并确保转发给 api.tikuhai.com 的数据格式正确。
3.2 问题一:无法正确解析 text/plain 请求体
- 现象:
curl发送Content-Type: text/plain请求时,服务器日志显示前端传入值: {}。 - 分析: Express 的
express.json()中间件默认只处理application/json请求,忽略text/plain。 - 解决方案:
- 在
src/app.js中添加app.use(express.text());中间件。 - 在
handleSearch函数中增加逻辑,当req.body为字符串时,使用JSON.parse()转换为对象。
- 在
3.3 问题二:因 options 字段类型不匹配导致 500 错误
- 现象: 特定用例 (
options字段为空字符串) 转发到api.tikuhai.com后返回 500 错误。 - 分析: 客户端传入
{"options": ""}会覆盖config.js中的默认空数组[]。后端服务预期options为数组,收到字符串导致处理失败。 - 解决方案: 在数据合并后、发送请求前,增加精准修正逻辑:
此方案确保了
1 2 3if (forwardData.options === '') { forwardData.options = []; }options字段在转发前始终为数组格式。
3.4 与 OCS 脚本对接及功能增强
问题一:修复 handler 答案解析逻辑
- 问题:
ocs-tiku-hi-adapter.json配置中handler函数返回值格式不符 OCS 规范。 - 解决方案: 修改
handler函数返回[题目, 答案]格式数组,并增加对多选题答案(#分隔)和接口错误信息([错误信息, undefined])的处理。
问题二:解决跨域请求 (CORS) 失败问题
- 问题: 浏览器从
https://i.chaoxing.com向本地服务发起请求时,因 CORS 策略导致OPTIONS预检请求返回403 Forbidden。 - 解决方案:
- 安装
corsnpm 包。 - 在
src/app.js中引入并配置cors中间件,明确允许来自https://i.chaoxing.com的跨域请求。
- 安装
问题三:增加接口 key 验证的调试开关
- 目标: 方便开发调试,临时关闭
key: '114514'验证。 - 解决方案: 在
src/config.js中增加disableKeyCheck布尔配置项,并在src/app.js中根据其值决定是否执行key验证逻辑。
问题四:规范化 options 参数处理
- 问题: 填空题等无选项请求缺少
options字段,需默认值确保转发格式正确。 - 解决方案:
- 在
src/config.js中为options设置默认值[]。 - 在
src/app.js中增加逻辑:若options存在且为字符串,则按\n分割为数组;若不存在,则使用配置中的默认空数组。确保转发给api.tikuhai.com的options始终为数组。
- 在
IV. 平台迁移与自动化部署 (Deno Deploy)
4.1 目标
将基于 Node.js 和 Express 的现有项目迁移到 Deno 平台,并配置通过 CI/CD 自动部署到 Deno Deploy。
4.2 已解决的核心问题
问题一:运行时环境不兼容
- 问题: 原始项目基于 Node.js、Express 和 CommonJS 模块,与 Deno 的原生运行时和 ES 模块系统不兼容。
- 解决方案: 创建新入口文件
deno_app.js,使用 Deno 内置的Deno.serve替换 Express 服务器,并手动将所有require转换为import。
问题二:依赖管理与移除 node_modules
- 问题: 项目依赖
axios和@faker-js/faker通过npm安装在node_modules目录,Deno Deploy 不支持。 - 解决方案:
axios替换为 Deno 内置的fetchAPI。@faker-js/faker通过 Deno 官方第三方模块库deno.land/x找到替代模块,直接通过 URL 导入 (https://deno.land/x/faker@v1.0.3/mod.ts)。
问题三:文件系统写入限制
- 问题: 原始应用将日志写入本地
request.log,Deno Deploy 生产环境文件系统只读。 - 解决方案: 将日志记录逻辑从写入文件修改为使用
console.log输出到标准输出。Deno Deploy 会自动捕获这些控制台日志并在线上仪表盘中展示。
问题四:自动化部署流程缺失
- 问题: 项目没有自动化部署流程,需手动操作。
- 解决方案: 创建 GitHub Actions 配置文件
.github/workflows/deploy.yml,配置 CI/CD 工作流。该工作流在代码推送到main分支时自动触发,使用deployctl工具将deno_app.js应用部署到 Deno Deploy。
4.3 最终成果
- 一个完全兼容 Deno 运行时的独立应用文件
deno_app.js。 - 一个可重复、可靠的自动化部署流程,定义在
.github/workflows/deploy.yml中。 - 项目现在已准备就绪,可通过 GitHub Actions 或本地命令行工具
deployctl轻松部署到 Deno Deploy 的全球边缘网络。
V. 总结与经验教训
本次项目开发与复盘涵盖了从 API 设计、前端对接、后端数据兼容性、开发环境优化,到最终的平台迁移和自动化部署的多个环节。
主要成就
- 成功开发并部署了
tikuAdapterAPI 端点,实现了与外部题库的对接及数据转换。 - 构建了高效的开发环境,通过 Node.js
--watch和端口占用问题解决,显著提升了开发效率。 - 增强了服务器对多种
Content-Type请求的解析能力,并通过防御性编程和特定边缘用例处理,极大提升了数据处理的健壮性和兼容性。 - 成功将项目从 Node.js 环境平滑迁移至 Deno 平台,并建立了完善的 CI/CD 自动化部署流程。
经验教训
Content-Type的重要性:在处理HTTP请求时,严格理解和遵守Content-Type至关重要。例如,Express 的中间件默认只处理application/json,对于text/plain或其他类型需要显式配置。这是一个深刻的教训。- 防御性编程:在处理可能来自用户或外部接口的数据时,应始终预设数据可能不完整或格式不正确,通过添加空值判断、默认值或类型转换来避免运行时错误,提高代码健壮性。
- 开发工具的利用:善用平台提供的原生开发工具(如 Node.js
--watch)可以减少对第三方依赖的引入,保持项目轻量。 - 系统诊断能力:掌握
netstat、taskkill等命令行工具对于诊断和解决环境问题(如端口占用)至关重要。 - 平台特性考量:在进行平台迁移时,必须全面了解目标平台的运行时特性(如模块系统、文件系统限制、网络API),并相应地调整代码和依赖管理。
- CI/CD 自动化:早期规划并实现自动化部署流程,可以大幅减少手动部署的错误,并提高发布效率和一致性。
本次复盘为未来的项目开发积累了宝贵的经验,使团队在处理复杂系统集成和部署问题时更加成熟和高效。