Files
jiapu/docs/superpowers/plans/2026-07-10-axios-request-layer-refactor.md
T

9.9 KiB

Axios 公共请求层重构 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 删除现有 fetch 请求实现,以本地 Axios 浏览器版和 utils/AxiosRequestUtil.js 替换为唯一公共请求层,页面业务 JS 不再依赖或实现底层网络请求。

Architecture: utils/axios.js 是固定版本的第三方浏览器依赖;utils/AxiosRequestUtil.js 负责 Axios 实例、请求头、token、参数、响应解包和错误转换;utils/ApiClient.js 负责所有 PC 接口契约与 token 生命周期。所有页面在页面业务脚本前加载三个 utils 文件,旧 utils/RequestUtil.jspublic/js/api-client.js 被删除且不保留兼容入口。

Tech Stack: Axios 1.7.9 浏览器非压缩构建、原生 JavaScript、Node assert 测试、PowerShell 静态扫描。

Global Constraints

  • 计划创建时间:2026-07-10 09:27:30 +08:00。
  • utils 只存通用依赖和公共请求封装;public/js 只存页面业务脚本,不存 API 客户端或底层请求实现。
  • 不保留 fetchfetchImplroot.fetchRequestUtilpublic/js/api-client.js 或旧脚本引用;不做 Axios/fetch 双实现兼容。
  • Axios 使用本地 utils/axios.js,页面运行时不依赖 CDN。
  • 普通 JSON 请求传对象给 Axios;文件上传传 FormData;不手写 JSON 字符串。
  • 每个请求都带 clientid;有 token 且 auth !== false 时带 Authorization: Bearer <token>
  • PC-014 在本重构完成后重新执行,重构前的复核结论不作为最终证据。

Task 0: 收敛环境配置职责

Files:

  • Modify: config.js
  • Modify: tests/config.test.js
  • Modify: utils/ApiClient.js

Interfaces:

  • Produces: GenealogyConfig.getEnvironment(),只返回 developmentproduction

  • Produces: GenealogyConfig.getApiBaseUrl(),只返回当前环境的接口基础地址。

  • Produces: GenealogyConfig.getConfig(),只返回 { environment, apiBaseUrl }

  • Consumes: ApiClient 自己定义 PC clientIdtenantId、token key 和 token header。

  • Step 1: 写配置职责失败测试

assert.deepStrictEqual(config.getConfig(), {
  environment: 'development',
  apiBaseUrl: 'http://test-genealogy-api.ddxcjp.cn'
});
assert.strictEqual(config.getClientId, undefined);
assert.strictEqual(config.getTenantId, undefined);
assert.strictEqual(config.getTokenKey, undefined);
  • Step 2: 运行测试确认旧配置职责过宽

Run: node tests\\config.test.js

Expected: FAIL,旧配置仍暴露 clientId、tenantId、token key 或 token header。

  • Step 3: 重写 config.js 为环境和域名唯一入口
var environments = {
  development: { apiBaseUrl: 'http://test-genealogy-api.ddxcjp.cn' },
  production: { apiBaseUrl: 'http://test-genealogy-api.ddxcjp.cn' }
};

function getConfig() {
  return {
    environment: getEnvironment(),
    apiBaseUrl: getApiBaseUrl()
  };
}
  • Step 4: 将 PC 身份和 token 常量保留在 ApiClient
var DEFAULT_CLIENT_ID = 'ced7e5f0498645c6ec642dcf450b036f';
var DEFAULT_TENANT_ID = '000000';
var DEFAULT_TOKEN_KEY = 'genealogy_auth_token';
var DEFAULT_TOKEN_HEADER_NAME = 'Authorization';

补充约束:ApiClient 不定义接口基础地址;必须由根目录 config.jsapiBaseUrl 或调用方显式 baseUrl 提供。

  • Step 5: 运行配置与 API 客户端测试

Run: node tests\\config.test.js; node tests\\api-client.test.js; node --check config.js; node --check utils\\ApiClient.js

Expected: 所有命令通过。

Task 1: 锁定 Axios 请求契约的失败测试

Files:

  • Modify: tests/utils.test.js
  • Modify: tests/api-client.test.js

Interfaces:

  • Produces: AxiosRequestUtil.createRequester(options)

  • Consumes: options.axiosInstance,该对象实现 request(config)

  • Produces: request(method, path, { query, body, headers, auth }),向 Axios 传入 { method, url, params, data, headers }

  • Step 1: 把工具测试改为 Axios 假实例

const axiosCalls = [];
const requester = AxiosRequestUtil.createRequester({
  baseUrl: 'https://api.example.test',
  clientId: 'pc-client',
  getToken: () => 'token-x',
  axiosInstance: {
    request: async (config) => {
      axiosCalls.push(config);
      return { status: 200, data: { code: 200, data: { ok: true } } };
    }
  }
});
  • Step 2: 运行测试确认因旧 fetch 契约失败

Run: node tests\\utils.test.js; node tests\\api-client.test.js

Expected: FAIL,提示缺少 AxiosRequestUtil 或仍使用 fetchImpl

Task 2: 创建 Axios 工具层并删除 fetch 工具层

Files:

  • Create: utils/axios.js
  • Create: utils/AxiosRequestUtil.js
  • Create: utils/ApiClient.js
  • Delete: utils/RequestUtil.js
  • Delete: public/js/api-client.js

Interfaces:

  • AxiosRequestUtil.createRequester(options) 只接受 Axios 实例,不接受 fetchImpl

  • GenealogyApi.createClient(options)utils/ApiClient.js 提供,只接受 axiosInstance 测试注入;生产环境读取 window.axios

  • Step 1: 下载固定 Axios 非压缩浏览器构建

Run: curl.exe --fail --location https://cdn.jsdelivr.net/npm/axios@1.7.9/dist/axios.js --output utils\\axios.js

Expected: utils/axios.js 存在且首行包含 Axios 版本信息。

  • Step 2: 实现 AxiosRequestUtil 最小请求流程
var response = await axiosInstance.request({
  method: method.toLowerCase(),
  url: path,
  params: requestOptions.query,
  data: requestOptions.body,
  headers: headers
});

return unwrapResponse(response.data);
  • Step 3: 从零实现 utils/ApiClient.js 并只依赖 AxiosRequestUtil
var requestUtil = getAxiosRequestUtil();
var requester = requestUtil.createRequester({
  baseUrl: baseUrl,
  clientId: clientId,
  getToken: getToken,
  axiosInstance: settings.axiosInstance || root.axios
});
  • Step 4: 删除旧 fetch 请求文件和旧公共 API 文件

Run: Remove-Item -LiteralPath utils\\RequestUtil.js; Remove-Item -LiteralPath public\\js\\api-client.js

Expected: 两个文件不存在,后续扫描无 RequestUtilfetchImplroot.fetchfetch(public/js/api-client.js 匹配。

  • Step 5: 运行工具和 API 客户端测试

Run: node tests\\utils.test.js; node tests\\api-client.test.js; node --check utils\\AxiosRequestUtil.js; node --check utils\\ApiClient.js

Expected: 所有命令通过。

Task 3: 更新页面公共脚本顺序

Files:

  • Modify: 所有根目录中加载 public/js/api-client.jsutils/ApiClient.js 的 HTML 页面。

  • Test: tests/auth-page-structure.test.js

  • Test: tests/api-script-order.test.js

  • Step 1: 以自动发现的脚本顺序测试锁定页面依赖

assert.strictEqual(pages.length, 45);
assert.ok(axiosIndex < axiosRequestUtilIndex);
assert.ok(axiosRequestUtilIndex < apiClientIndex);
assert.strictEqual(html.includes('utils/RequestUtil.js'), false);
  • Step 2: 运行测试确认旧脚本顺序不满足新契约

Run: node tests\\auth-page-structure.test.js

Expected: FAIL,仍有页面加载旧 API 客户端或未加载 Axios 和 AxiosRequestUtil。

  • Step 3: 逐页替换公共脚本引用
<script src="utils/axios.js"></script>
<script src="utils/AxiosRequestUtil.js"></script>
<script src="utils/ApiClient.js"></script>
  • Step 4: 运行结构测试和静态扫描

Run: node tests\\auth-page-structure.test.js; rg -n "utils/RequestUtil\\.js|public/js/api-client\\.js|fetchImpl|root\\.fetch|fetch\\(" --glob "!public/tac/**" --glob "!utils/axios.js" .

Expected: 测试通过,旧请求层标识无匹配。

Task 4: 重跑 PC 复核并更新记录

Files:

  • Modify: docs/pc-api-page-integration-tracker-2026-07-09.md

  • Modify: docs/superpowers/plans/2026-07-10-axios-request-layer-refactor.md

  • Modify: docs/superpowers/plans/2026-07-10-pc-tracker-reverification.md

  • Step 1: 运行所有 Node 测试与语法检查

Run: Get-ChildItem -Path tests -Filter *.test.js | Sort-Object Name | ForEach-Object { node $_.FullName }; node --check utils\\AxiosRequestUtil.js; node --check utils\\ApiClient.js; git diff --check

Expected: 所有测试通过,语法检查和差异检查无错误。

  • Step 2: 执行 PC-014 复核命令并记录外部网关状态

Run: curl.exe -I --max-time 15 http://test-genealogy-api.ddxcjp.cn/captcha/require

Expected: 记录当次结果;仅本地验证通过的项标为“本地复核通过”,网关不可用时标注“外部环境待验证”。

  • Step 3: 写入完成时间和清理结论

Record: Axios 文件来源、删除的 fetch 文件、页面脚本替换范围、所有验证命令及结果。

自检

  • 所有底层网络调用都从 utils/AxiosRequestUtil.js 发起。
  • public/js 中不含 fetch、Axios 实例创建或请求头拼装。
  • 所有页面在页面业务脚本前加载 utils/axios.jsutils/AxiosRequestUtil.jsutils/ApiClient.js
  • utils/RequestUtil.jspublic/js/api-client.jsfetchImplroot.fetch 和旧页面脚本引用均不存在。

完成记录

  • 完成时间:2026-07-10 10:10:56 +08:00。
  • Axios 来源:axios@1.7.9/dist/axios.js 的本地非压缩浏览器构建,存放于 utils/axios.js
  • 请求契约:所有 PC 请求均由 utils/AxiosRequestUtil.js 通过 axios.request 发起;utils/ApiClient.js 仅封装 PC 接口和 token 生命周期。
  • 配置边界:根目录 config.js 是接口基础地址唯一来源;ApiClient 不再保存 DEFAULT_BASE_URL
  • 页面范围:45 个加载接口客户端的 HTML 页面已统一脚本顺序;旧 utils/RequestUtil.jspublic/js/api-client.js 已删除。
  • 验证:全量 Node 测试、语法检查、45 页脚本顺序检查、旧 fetch/旧脚本扫描和 git diff --check 均通过。