Skip to content

refactor(http-factory): fix defaultIsRefreshFailure, add test coverage, update docs - #21

Merged
fengzai6 merged 8 commits into
mainfrom
enhance-http
Jul 6, 2026
Merged

refactor(http-factory): fix defaultIsRefreshFailure, add test coverage, update docs#21
fengzai6 merged 8 commits into
mainfrom
enhance-http

Conversation

@fengzai6

@fengzai6 fengzai6 commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • fix: defaultIsRefreshFailure 非 AxiosError(如业务代码抛出的 Error)现在正确视为鉴权失败,触发 onAuthFailure;网络错误 / 500 服务端错误仍不视为鉴权失败
  • test: 新增 4 个工具函数单元测试文件(error / refresh / retry-policy / token),新增 3 个 integration 测试(onBusinessResponse 替换响应、网络错误重试、自定义 generateKey),共 119 个测试全部通过
  • docs: 更新 reference/http-demo.ts(移除冗余自定义 isRefreshFailure,补充 retryPolicy / dedupePolicy / headersProvider 示例)和 README.md(配置项文档、流程说明、测试覆盖清单)

改动文件

  • utils/refresh.ts — 修复 defaultIsRefreshFailure,非 AxiosError 返回 true
  • __tests__/http-client.error.test.ts — 新增,normalizeError / invokeOnError 单元测试
  • __tests__/http-client.refresh.test.ts — 新增,shouldSkipRefresh / defaultIsRefreshFailure 单元测试
  • __tests__/http-client.retry-policy.test.ts — 新增,defaultShouldRetry / defaultRetryDelay / resolveRetryPolicy 单元测试
  • __tests__/http-client.token.test.ts — 新增,formatAccessToken / normalizeTokenResult 单元测试
  • __tests__/http-client.test.ts — 新增 3 个 integration 测试
  • __tests__/http-client.edge-cases.test.ts — 修复 3 个断言(对齐修复后行为)
  • __tests__/http-client.cooldown.test.ts — 场景 6 网络错误改用 AxiosError(更贴近真实场景)
  • reference/http-demo.ts — 补充新功能示例,移除冗余自定义 isRefreshFailure
  • reference/README.md — 全量更新文档

Test plan

  • npx vitest run apps/web/src/services/api/http-factory/__tests__/ 全部 119 个测试通过

Summary by CodeRabbit

  • 新功能

    • HTTP 请求现在支持动态请求头注入、请求去重、通用重试策略,以及更灵活的业务响应拦截与错误回调。
    • 刷新令牌流程新增冷却期与并发合并,减少重复刷新并提升稳定性。
    • 默认刷新缓冲时间在非开发环境启用,令牌将更早进入刷新流程。
  • Bug 修复

    • 改进错误状态识别,兼容更多错误结构与嵌套响应场景。
    • 统一鉴权失败与刷新失败的错误提示,减少异常文案不一致的问题。
  • 文档

    • 更新了 HTTP 客户端使用说明与配置示例。

@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
my-first-nest Skipped Skipped Jul 6, 2026 1:26am

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@fengzai6, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8a681663-7c63-47f8-a23b-778d0abf1483

📥 Commits

Reviewing files that changed from the base of the PR and between 505fe9c and 3db83e7.

📒 Files selected for processing (8)
  • apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.token-normalization.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.token.test.ts
  • apps/web/src/services/api/http-factory/constants.ts
  • apps/web/src/services/api/http-factory/dedupe-manager.ts
  • apps/web/src/services/api/http-factory/types/http-client-options.ts
  • apps/web/src/services/api/http-factory/utils/refresh.ts
  • package.json

Walkthrough

本次改动重写了 apps/web/src/services/api/http-factory 模块:引入统一的 normalizeError/invokeOnError 错误处理、TokenRefreshManager 冷却与并发去重、DedupeManager 请求合并、可配置重试策略、headersProvider 动态请求头及 onBusinessResponse 钩子,重构类型体系并同步更新测试、文档与示例配置,另有小幅无关调整(.gitignore、CLAUDE.md 符号链接、cache-capabilities 错误状态提取)。

Changes

HTTP 客户端核心重构

Layer / File(s) Summary
类型与常量定义
.../types/token.ts, .../types/common.ts, .../types/http-client-options.ts, .../constants.ts, .../types.ts
新增 AccessTokenResultRequestRetryStateErrorContextErrorMessagesHttpClientOptions/ResolvedHttpClientOptionsDedupePolicy/RetryPolicy 类型及 DEFAULT_MESSAGES/DEFAULT_REFRESH_BUFFER_MS 常量,移除旧 types.ts 中的等价定义。
错误标准化、Token 与刷新工具函数
.../utils/error.ts, .../utils/token.ts, .../utils/refresh.ts, .../__tests__/http-client.{error,token,refresh,retry-policy}.test.ts
新增 normalizeError/invokeOnErrorformatAccessToken/normalizeTokenResult/isTokenExpiringSoonshouldSkipRefresh/defaultIsRefreshFailure/defaultShouldRetry/defaultRetryDelay/resolveRetryPolicy,并新增对应单元测试。
请求去重管理器
.../dedupe-manager.ts
新增 DedupeManager 类,基于时间窗口缓存并复用相同请求的 Promise。
TokenRefreshManager 冷却与并发去重
.../token-refresh-manager.ts
新增 REFRESH_SKIPPED 标记与冷却时间控制,runRefresh 在冷却期内跳过刷新并复用进行中的刷新 Promise。
createHttpClient 核心流程重写
.../index.ts
请求/响应拦截器改用统一错误处理、headersProvider 动态注入、onBusinessResponse 业务拦截、通用重试策略与刷新流程整合。
配套测试更新、文档与示例调整
.../__tests__/http-client.{test,edge-cases,cooldown}.test.ts, .../reference/README.md, .../reference/http-demo.ts, apps/web/src/services/api/new-http.ts, apps/web/src/pages/cache-capabilities/index.tsx, .codegraph/.gitignore, CLAUDE.md
更新测试断言由 HttpError 改为通用 Error,新增 headersProvider/retryPolicy/dedupePolicy/onBusinessResponse 测试组,同步更新 README 与示例配置,另有无关的 gitignore、符号链接与错误状态提取调整。

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • fengzai6/my-first-nest#13: 本次 PR 直接重构和扩展了该 PR 引入的 http-factory 模块(index.ts、token-refresh-manager.ts、utils/types)。
  • fengzai6/my-first-nest#16: 本次 PR 中 AccessTokenDetail/token 归一化逻辑对 expiresAt 多类型兼容,与该 PR 中令牌过期时间字段调整相关联。
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次对 http-factory 的重构重点,包含 defaultIsRefreshFailure 修复、测试补充和文档更新。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch enhance-http

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/src/services/api/http-factory/index.ts (1)

155-178: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

retryAfterRefresh 这里会重复调用 onError

refreshAccessToken() 的失败分支已经走过一次 invokeOnError({ type: "refresh" });这里的 catch 又会再包一层。instance.request(config) 的重试失败也会先在响应拦截器里触发一次 invokeOnError,随后再次进入这里被重复处理。这样 onError 可能被触发两次以上,并且错误会被二次转换。这里应直接抛出标准化后的错误,不要再次调用 invokeOnError

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/index.ts` around lines 155 - 178,
`retryAfterRefresh` 里的 catch 会重复触发 `onError` 并二次包装错误,因为 `refreshAccessToken()` 和
`instance.request(config)` 的失败已经在其他拦截器路径里调用过 `invokeOnError`。请在该分支中保留
`normalizeError(error)` 的标准化结果,但直接抛出它,不要再次调用 `invokeOnError`;重点检查
`retryAfterRefresh`、`refreshAccessToken` 和 `instance.request`
这条重试链路,避免重复上报和重复转换。
🧹 Nitpick comments (11)
apps/web/src/services/api/http-factory/types/token.ts (1)

4-7: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

接口命名未遵循 I 前缀规范。

AccessTokenDetail 是接口(interface),按仓库规范应命名为 IAccessTokenDetail

As per coding guidelines: "Use PascalCase for type and interface names, with I prefix for interfaces (e.g., IUser)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/types/token.ts` around lines 4 - 7,
The interface name does not follow the repository’s `I` prefix convention.
Update the `AccessTokenDetail` interface in `token.ts` to use the required
interface naming style, and make sure any references to `AccessTokenDetail`
elsewhere are renamed to match the new `IAccessTokenDetail` symbol.

Source: Coding guidelines

apps/web/src/services/api/http-factory/types/http-client-options.ts (1)

13-29: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

多个接口未遵循 I 前缀命名规范。

DedupePolicyRetryPolicyHttpClientOptions 均为接口,按仓库规范应命名为 IDedupePolicyIRetryPolicyIHttpClientOptions

As per coding guidelines: "Use PascalCase for type and interface names, with I prefix for interfaces (e.g., IUser)".

Also applies to: 42-57, 65-68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/types/http-client-options.ts` around
lines 13 - 29, Rename the interface types to follow the repository’s
`I`-prefixed PascalCase convention: change `DedupePolicy`, `RetryPolicy`, and
`HttpClientOptions` to `IDedupePolicy`, `IRetryPolicy`, and `IHttpClientOptions`
in the `http-client-options` types module. Update any related references in the
same file and nearby type usages so the exported API and all consumers continue
to compile with the new names.

Source: Coding guidelines

apps/web/src/services/api/http-factory/types/common.ts (1)

6-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

多个接口未遵循 I 前缀命名规范。

RequestRetryStateErrorContextErrorMessages 均为接口,按仓库规范应分别命名为 IRequestRetryStateIErrorContextIErrorMessages

As per coding guidelines: "Use PascalCase for type and interface names, with I prefix for interfaces (e.g., IUser)".

Also applies to: 24-29, 34-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/types/common.ts` around lines 6 - 11,
Rename the interface types in common.ts to match the repository’s `I`-prefix
convention: change `RequestRetryState`, `ErrorContext`, and `ErrorMessages` to
`IRequestRetryState`, `IErrorContext`, and `IErrorMessages`. Update any
references to these symbols across the related HTTP factory types and usages so
the renamed interfaces remain consistent and compile cleanly.

Source: Coding guidelines

apps/web/src/services/api/http-factory/__tests__/http-client.refresh.test.ts (2)

5-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

无效的 axios mock,未改变任何行为。

该 mock 只是原样重建 axios 模块的 isAxiosError,没有实际替换逻辑,属于冗余代码,可以直接移除,测试会使用真实的 axios.isAxiosError 达到相同效果。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.refresh.test.ts`
around lines 5 - 15, The axios mock in the http-client.refresh test is redundant
because it only re-exposes the real isAxiosError behavior without changing
anything. Remove the vi.mock("axios", ...) block from the test setup so the
suite uses the actual axios implementation directly, and keep the rest of the
test file unchanged.

17-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

makeAxiosError 辅助函数与 http-client.retry-policy.test.ts 中的实现重复。

两个文件的 makeAxiosError 逻辑几乎相同(仅多了 code 字段),建议提取到共享测试工具文件中以减少重复维护成本。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.refresh.test.ts`
around lines 17 - 31, The test helper makeAxiosError is duplicated between this
suite and http-client.retry-policy.test.ts, so the error construction logic
should be shared instead of maintained in two places. Move the common AxiosError
factory into a reusable test utility and update http-client.refresh.test.ts to
import it, keeping only the extra code field handling here if needed. Use the
existing makeAxiosError symbol in both tests as the reference point when
extracting the shared helper.
apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts (2)

21-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

makeAxiosErrorhttp-client.refresh.test.ts 中的实现重复。

建议提取共享测试工具函数,减少重复维护成本。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts`
around lines 21 - 35, The makeAxiosError helper in
http-client.retry-policy.test.ts duplicates the same AxiosError setup used in
http-client.refresh.test.ts, so extract this shared test utility into a common
test helper and reuse it from both specs. Move the reusable helper into a shared
location near the existing http-client test helpers, then update the
retry-policy and refresh tests to import and call that shared function instead
of maintaining separate copies.

9-19: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

无效的 axios mock,未改变任何行为。

http-client.refresh.test.ts 中相同,该 mock 只是原样重建 axios 模块,未实际改变行为,可以移除。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts`
around lines 9 - 19, The axios mock in the http-client retry policy test is
redundant because it simply recreates the real module without changing behavior.
Remove the vi.mock("axios", ...) setup from the retry-policy test file and keep
the test using the actual axios export behavior, matching the approach used in
http-client.refresh.test.ts.
apps/web/src/services/api/http-factory/__tests__/http-client.token.test.ts (1)

42-116: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

多处使用 as any 绕过类型检查。

按编码规范应避免 any 类型。这里可以改用更精确的类型断言(例如 as unknown as AccessTokenResult)或直接构造符合联合类型的非法分支值,减少 any 的滥用。鉴于这是测试文件且影响有限,优先级不高。

As per coding guidelines, "Forbid any type; prioritize using existing project type definitions" for **/*.{ts,tsx}.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.token.test.ts`
around lines 42 - 116, 测试用例里多处通过 as any 绕过了类型检查,违反了禁止 any 的规范。请在
http-client.token.test.ts 中的 normalizeTokenResult
相关断言里,改用更精确的类型断言或直接构造符合项目类型定义的输入,优先复用 AccessTokenResult 等已有类型,避免 any 出现在测试代码中。

Source: Coding guidelines

apps/web/src/services/api/http-factory/__tests__/http-client.test.ts (3)

856-868: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

避免使用 any 类型。

866 行 config: {} as any 违反项目对 TypeScript 文件禁止 any 类型的规范,建议改为对整个 mock 响应对象做类型断言,而非在字段上使用 any

♻️ 建议修复
-        onBusinessResponse: () => ({
-          status: 200,
-          data: { replaced: true },
-          statusText: "OK",
-          headers: {},
-          config: {} as any,
-        }),
+        onBusinessResponse: () =>
+          ({
+            status: 200,
+            data: { replaced: true },
+            statusText: "OK",
+            headers: {},
+            config: {},
+          }) as AxiosResponse,

As per coding guidelines, "Forbid any type; prioritize using existing project type definitions" (**/*.{ts,tsx}).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.test.ts` around
lines 856 - 868, The test mock in onBusinessResponse uses a field-level any cast
on config, which violates the no-any rule. Update the http-client.test.ts
fixture in the onBusinessResponse case by typing the whole mocked AxiosResponse
object with the existing AxiosResponse type (or an equivalent project type)
instead of using config: {} as any, so the createHttpClient test remains
type-safe without any.

Source: Coding guidelines


608-646: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

建议为 fake timers 增加 try/finally 保护。

若 640-643 行的断言失败,vi.useRealTimers()(645 行)不会被执行,fake timer 状态会泄漏到后续用例,导致连锁性、难以定位的测试失败。

♻️ 建议修复
-      const responsePromise = http.get("/profile");
-      await vi.advanceTimersByTimeAsync(2000);
-      const response = await responsePromise;
-
-      expect(response.data).toEqual({ ok: true });
-
-      vi.useRealTimers();
+      try {
+        const responsePromise = http.get("/profile");
+        await vi.advanceTimersByTimeAsync(2000);
+        const response = await responsePromise;
+
+        expect(response.data).toEqual({ ok: true });
+      } finally {
+        vi.useRealTimers();
+      }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.test.ts` around
lines 608 - 646, Test case in http-client.test.ts uses vi.useFakeTimers()
without guaranteed cleanup, so a failure before the end leaves fake timers
enabled for later tests. Wrap the body of the retry test around the
createHttpClient, queueMatchedHandler, and response assertions in a try/finally
block, and move vi.useRealTimers() into the finally so timer state is always
restored even if the assertions fail.

377-876: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

考虑拆分测试文件。

本次改动后该文件已明显超过 500 行(新增了 headersProvider/retryPolicy/dedupePolicy/onBusinessResponse 四个较大的 describe 块)。PR 中已有将测试按关注点拆分为独立文件的先例(如 http-client.cooldown.test.tshttp-client.edge-cases.test.ts),建议按同样思路将新增的 describe 块拆分为独立文件(如 http-client.headers-provider.test.tshttp-client.dedupe-policy.test.ts 等),便于维护。

As per coding guidelines, "Consider splitting files that exceed 500 lines into smaller modules" (**/*.{ts,tsx}).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.test.ts` around
lines 377 - 876, The http-client test file has grown beyond the size guideline
and now contains several large, unrelated describe blocks, so split the new
coverage into focused test files to improve maintainability. Move the
headersProvider, retryPolicy, dedupePolicy, and onBusinessResponse suites out of
http-client.test.ts into separate spec files, following the existing pattern
used by http-client.cooldown.test.ts and http-client.edge-cases.test.ts, and
keep each file centered on one concern while preserving the same test setup
helpers and coverage.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts`:
- Line 2: The test file has an unused default import from axios that triggers
TS6133 and breaks the build. Update the import in
http-client.retry-policy.test.ts to keep only the used named symbol AxiosError
and remove the axios default import; verify no other references in the test rely
on axios so the import list stays minimal.

In `@apps/web/src/services/api/http-factory/dedupe-manager.ts`:
- Around line 3-6: The interface name in dedupe-manager.ts should follow the
project’s interface naming convention by adding the I prefix. Rename
PendingRequest to IPendingRequest and update all references in the same module,
including the Map<string, PendingRequest> type annotation and any related
usages, so the types stay consistent with the new identifier.
- Around line 76-82: The cleanup in dedupe-manager’s promise handling is
creating an unobserved derived Promise via promise.finally(...), which can
surface as unhandledrejection when the original request rejects. Update the
logic in the dedupe manager to avoid discarding the returned Promise by
switching to a handled cleanup path such as promise.then(cleanup, cleanup), or
otherwise explicitly consume the result of finally() while preserving the
current pending-map guard keyed by key/current.promise.

In `@apps/web/src/services/api/http-factory/types/http-client-options.ts`:
- Around line 141-150: The documentation for isRefreshFailure in
http-client-options.ts is out of sync with the actual default behavior in
defaultIsRefreshFailure. Update the comment for isRefreshFailure so it matches
the real logic: non-Axios errors are treated as refresh failures, and the
existing status-code and authFailureCodes rules remain unchanged. Use the
isRefreshFailure option and defaultIsRefreshFailure symbol to locate the
affected docblock and keep the wording consistent with the implementation.

---

Outside diff comments:
In `@apps/web/src/services/api/http-factory/index.ts`:
- Around line 155-178: `retryAfterRefresh` 里的 catch 会重复触发 `onError` 并二次包装错误,因为
`refreshAccessToken()` 和 `instance.request(config)` 的失败已经在其他拦截器路径里调用过
`invokeOnError`。请在该分支中保留 `normalizeError(error)` 的标准化结果,但直接抛出它,不要再次调用
`invokeOnError`;重点检查 `retryAfterRefresh`、`refreshAccessToken` 和
`instance.request` 这条重试链路,避免重复上报和重复转换。

---

Nitpick comments:
In
`@apps/web/src/services/api/http-factory/__tests__/http-client.refresh.test.ts`:
- Around line 5-15: The axios mock in the http-client.refresh test is redundant
because it only re-exposes the real isAxiosError behavior without changing
anything. Remove the vi.mock("axios", ...) block from the test setup so the
suite uses the actual axios implementation directly, and keep the rest of the
test file unchanged.
- Around line 17-31: The test helper makeAxiosError is duplicated between this
suite and http-client.retry-policy.test.ts, so the error construction logic
should be shared instead of maintained in two places. Move the common AxiosError
factory into a reusable test utility and update http-client.refresh.test.ts to
import it, keeping only the extra code field handling here if needed. Use the
existing makeAxiosError symbol in both tests as the reference point when
extracting the shared helper.

In
`@apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts`:
- Around line 21-35: The makeAxiosError helper in
http-client.retry-policy.test.ts duplicates the same AxiosError setup used in
http-client.refresh.test.ts, so extract this shared test utility into a common
test helper and reuse it from both specs. Move the reusable helper into a shared
location near the existing http-client test helpers, then update the
retry-policy and refresh tests to import and call that shared function instead
of maintaining separate copies.
- Around line 9-19: The axios mock in the http-client retry policy test is
redundant because it simply recreates the real module without changing behavior.
Remove the vi.mock("axios", ...) setup from the retry-policy test file and keep
the test using the actual axios export behavior, matching the approach used in
http-client.refresh.test.ts.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.test.ts`:
- Around line 856-868: The test mock in onBusinessResponse uses a field-level
any cast on config, which violates the no-any rule. Update the
http-client.test.ts fixture in the onBusinessResponse case by typing the whole
mocked AxiosResponse object with the existing AxiosResponse type (or an
equivalent project type) instead of using config: {} as any, so the
createHttpClient test remains type-safe without any.
- Around line 608-646: Test case in http-client.test.ts uses vi.useFakeTimers()
without guaranteed cleanup, so a failure before the end leaves fake timers
enabled for later tests. Wrap the body of the retry test around the
createHttpClient, queueMatchedHandler, and response assertions in a try/finally
block, and move vi.useRealTimers() into the finally so timer state is always
restored even if the assertions fail.
- Around line 377-876: The http-client test file has grown beyond the size
guideline and now contains several large, unrelated describe blocks, so split
the new coverage into focused test files to improve maintainability. Move the
headersProvider, retryPolicy, dedupePolicy, and onBusinessResponse suites out of
http-client.test.ts into separate spec files, following the existing pattern
used by http-client.cooldown.test.ts and http-client.edge-cases.test.ts, and
keep each file centered on one concern while preserving the same test setup
helpers and coverage.

In `@apps/web/src/services/api/http-factory/__tests__/http-client.token.test.ts`:
- Around line 42-116: 测试用例里多处通过 as any 绕过了类型检查,违反了禁止 any 的规范。请在
http-client.token.test.ts 中的 normalizeTokenResult
相关断言里,改用更精确的类型断言或直接构造符合项目类型定义的输入,优先复用 AccessTokenResult 等已有类型,避免 any 出现在测试代码中。

In `@apps/web/src/services/api/http-factory/types/common.ts`:
- Around line 6-11: Rename the interface types in common.ts to match the
repository’s `I`-prefix convention: change `RequestRetryState`, `ErrorContext`,
and `ErrorMessages` to `IRequestRetryState`, `IErrorContext`, and
`IErrorMessages`. Update any references to these symbols across the related HTTP
factory types and usages so the renamed interfaces remain consistent and compile
cleanly.

In `@apps/web/src/services/api/http-factory/types/http-client-options.ts`:
- Around line 13-29: Rename the interface types to follow the repository’s
`I`-prefixed PascalCase convention: change `DedupePolicy`, `RetryPolicy`, and
`HttpClientOptions` to `IDedupePolicy`, `IRetryPolicy`, and `IHttpClientOptions`
in the `http-client-options` types module. Update any related references in the
same file and nearby type usages so the exported API and all consumers continue
to compile with the new names.

In `@apps/web/src/services/api/http-factory/types/token.ts`:
- Around line 4-7: The interface name does not follow the repository’s `I`
prefix convention. Update the `AccessTokenDetail` interface in `token.ts` to use
the required interface naming style, and make sure any references to
`AccessTokenDetail` elsewhere are renamed to match the new `IAccessTokenDetail`
symbol.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 04fc2344-d2fb-49dd-877e-9934265cca3f

📥 Commits

Reviewing files that changed from the base of the PR and between f7863b1 and 505fe9c.

📒 Files selected for processing (24)
  • .codegraph/.gitignore
  • CLAUDE.md
  • apps/web/src/pages/cache-capabilities/index.tsx
  • apps/web/src/services/api/http-factory/__tests__/http-client.cooldown.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.edge-cases.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.error.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.refresh.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.token.test.ts
  • apps/web/src/services/api/http-factory/constants.ts
  • apps/web/src/services/api/http-factory/dedupe-manager.ts
  • apps/web/src/services/api/http-factory/index.ts
  • apps/web/src/services/api/http-factory/reference/README.md
  • apps/web/src/services/api/http-factory/reference/http-demo.ts
  • apps/web/src/services/api/http-factory/token-refresh-manager.ts
  • apps/web/src/services/api/http-factory/types.ts
  • apps/web/src/services/api/http-factory/types/common.ts
  • apps/web/src/services/api/http-factory/types/http-client-options.ts
  • apps/web/src/services/api/http-factory/types/token.ts
  • apps/web/src/services/api/http-factory/utils/error.ts
  • apps/web/src/services/api/http-factory/utils/refresh.ts
  • apps/web/src/services/api/http-factory/utils/token.ts
  • apps/web/src/services/api/new-http.ts
💤 Files with no reviewable changes (1)
  • apps/web/src/services/api/http-factory/types.ts

Comment thread apps/web/src/services/api/http-factory/__tests__/http-client.retry-policy.test.ts Outdated
Comment thread apps/web/src/services/api/http-factory/dedupe-manager.ts Outdated
Comment thread apps/web/src/services/api/http-factory/dedupe-manager.ts Outdated
Comment thread apps/web/src/services/api/http-factory/types/http-client-options.ts
fengzai6 added 2 commits July 6, 2026 09:03
…nhandledrejection,同步 isRefreshFailure 注释

- PendingRequest → IPendingRequest,接口加 I 前缀
- promise.finally() → void promise.then(cleanup, cleanup),避免派生 Promise 未消费导致 unhandledrejection
- isRefreshFailure JSDoc 同步修正为「非 AxiosError 视为刷新失败」
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 6, 2026
@fengzai6
fengzai6 merged commit 554da17 into main Jul 6, 2026
4 checks passed
@fengzai6
fengzai6 deleted the enhance-http branch July 6, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant