Skip to content

fix(http-factory): harden review P0/P1/P2 fixes - #22

Merged
fengzai6 merged 8 commits into
mainfrom
fix/http-factory-review-p0-p1
Jul 13, 2026
Merged

fix(http-factory): harden review P0/P1/P2 fixes#22
fengzai6 merged 8 commits into
mainfrom
fix/http-factory-review-p0-p1

Conversation

@fengzai6

@fengzai6 fengzai6 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

💻 变更类型 | Change Type

  • fix
  • refactor
  • test
  • docs

🔀 变更说明 | Description of Change

按 http-factory 高召回审查结论完成 P0/P1/P2 修复,重点收敛鉴权刷新、dedupe、错误处理与文档契约,避免错误登出、空 token 重试、请求挂起和配置误伤。

P0

  • 收窄 defaultIsRefreshFailure:非 AxiosError 默认不再自动鉴权失败
  • refresh 返回空 token 不进入冷却
  • 冷却期内空 token 不再重试原请求,直接走登录失效
  • 收紧 onBusinessResponse 响应替换判定,避免 {status,data} 业务对象误替换

P1

  • 去掉 __skipDedupe 字段,内部 refresh/retry 统一走 replayRequest
  • 统一 Authorization/token 判定:显式空 header 不覆盖;空 token 不注入
  • skipRefreshUrls 收窄为 exact/prefix,移除中间段滑动匹配
  • 同步 README / 类型注释契约

P2

  • 抽取 rejectWithError 收敛错误路径
  • request 拦截器中 token 与 headersProvider 并行获取
  • README 配置分层
  • new-http 增加中文 errorMessages

验证

  • yarn workspace @my-first-nest/web test src/services/api/http-factory
  • yarn workspace @my-first-nest/web type-check

📝 补充信息 | Additional Information

  • 任务文档:.tasks/2026-07-12-http-factory-high-recall-review/00-overview.md
  • expiresAt === 0 最终保持无效,不触发主动刷新

🔗 关联 Issue | Related Issue

Summary by CodeRabbit

  • 新功能

    • 401 失败优先走令牌刷新;刷新后重试会使用最新令牌与合并后的请求头。
    • 刷新/主动刷新异常、刷新返回空 token 等场景,错误会按预期回调并附带刷新上下文信息。
    • 相同进行中 GET 请求会复用结果,避免重复请求。
  • 改进

    • 跳过刷新 URL 改为仅支持精确路径或路径前缀匹配。
    • 默认错误提示统一为英文;并支持自定义登录过期文案。
    • 刷新失败配置项更名为 refreshFailureCodes(相关判定逻辑同步更新)。

fengzai6 added 7 commits July 12, 2026 18:08
Prevent double onError on refresh failure, keep headersProvider after explicit Authorization, prefer 401 refresh over generic retry, and make dedupe in-flight with configurable methods and stable keys.
Use neutral English default messages, rename authFailureCodes to refreshFailureCodes, and match skipRefreshUrls by path segments instead of substring includes.
Document and verify that proactive refresh failures still notify onError/onAuthFailure without blocking the current request.
@fengzai6 fengzai6 self-assigned this Jul 13, 2026
@vercel

vercel Bot commented Jul 13, 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 13, 2026 7:39am

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

HTTP 客户端行为

Layer / File(s) Summary
刷新失败判定与路径匹配
apps/web/src/services/api/http-factory/utils/refresh.ts, types/http-client-options.ts, constants.ts, new-http.ts, __tests__/http-client.refresh.test.ts, __tests__/http-client.edge-cases.test.ts
刷新失败配置改为 refreshFailureCodes,非 AxiosError 默认不视为鉴权失败;skipRefreshUrls 改为 exact/prefix 路径匹配,并覆盖空 token、冷却期和自定义判定场景。
请求去重与内部重放
apps/web/src/services/api/http-factory/dedupe-manager.ts, index.ts, types/http-client-options.ts, __tests__/http-client.test.ts
去重改为仅复用执行中的 GET Promise,默认 key 纳入规范化后的 method、baseURL、URL 和 params;刷新与通用重试通过内部重放绕过去重。
鉴权、重试与错误回调
apps/web/src/services/api/http-factory/index.ts, __tests__/http-client.test.ts, __tests__/http-client.edge-cases.test.ts, __tests__/http-client.token-normalization.test.ts
统一刷新异常和错误回调路径,401 优先于通用重试;请求支持显式空 Authorization、动态 headersProvider、刷新后重新注入 token,并严格识别完整 AxiosResponse。
文档与示例同步
apps/web/src/services/api/http-factory/reference/*, types/common.ts, reference/http-demo.ts
文档和示例同步新的刷新失败字段、错误消息、冷却、去重、重试顺序及响应替换规则。

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant HttpClient
  participant RefreshManager
  participant TokenStore
  Client->>HttpClient: 发起请求
  HttpClient-->>Client: 返回 401
  HttpClient->>RefreshManager: 执行或复用刷新
  RefreshManager->>TokenStore: 保存新 access token
  RefreshManager-->>HttpClient: 返回刷新结果
  HttpClient->>HttpClient: replayRequest 重试原请求
  HttpClient-->>Client: 返回最终响应或错误
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive 标题与 http-factory 相关,但过于笼统,未能清晰概括本次刷新、去重和错误处理的主要改动。 请改为更具体的单句标题,直接点出本次核心改动,例如刷新鉴权、请求去重或错误处理强化。
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/http-factory-review-p0-p1

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration.


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: 10

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)

71-98: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

instance.request 的去重拦截覆盖不到 http.get()
Axios 的 get/delete/head/options 别名方法绑定到内部 context,实际调用的是 context.request,不是外层重写后的 instance.request。这样 http.get() 仍会绕过去重逻辑;把去重放到 adapter/interceptor,或显式覆盖完整调用入口。

🤖 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 71 - 98, Update
the deduplication interception around instance.request so it also applies to
Axios alias methods such as get, delete, head, and options, whose calls use the
internal context.request. Move the GET deduplication logic into a shared
adapter/interceptor path or explicitly override all relevant request entry
points, while preserving request-level policy overrides and non-GET bypass
behavior.
🤖 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.edge-cases.test.ts`:
- Around line 507-545: 在“冷却期内 getAccessToken 为空时不重试原请求”测试中,补充对已声明的 onAuthFailure
mock 的调用断言,验证鉴权失败路径在抛出 Login session has expired 时也会调用该回调,并保持现有
refreshAccessToken 调用次数断言。

In
`@apps/web/src/services/api/http-factory/__tests__/http-client.refresh.test.ts`:
- Around line 42-69: 移除这些 shouldSkipRefresh 测试中的 as any,改用返回
InternalAxiosRequestConfig & RequestRetryState 的测试 helper,或复用现有测试配置类型构造请求配置;保持现有
URL 匹配断言不变,并确保测试继续遵循禁止 any 的类型约束。

In `@apps/web/src/services/api/http-factory/__tests__/http-client.test.ts`:
- Around line 1281-1305: Update the test “默认 key 会归一化 method 大小写并纳入 baseURL” to
issue concurrent requests with the same URL but different baseURL values, and
assert both requests are executed (requestCount equals 2). Preserve the existing
assertion that method case normalization deduplicates equivalent requests, while
explicitly verifying baseURL participates in the deduplication key.
- Around line 167-175: Remove the `any` types in `http-client.test.ts`: type
`retriedConfig` with a minimal structure containing the inspected `__skipDedupe`
field, and update the response handling around lines 1355–1364 to cast through
`unknown` before applying the project’s existing response type. Preserve the
current assertions and test behavior.

In
`@apps/web/src/services/api/http-factory/__tests__/http-client.token-normalization.test.ts`:
- Around line 179-268: Replace the fixed 10ms delays in both active-refresh
tests with deferred Promise synchronization. Resolve the deferred signal from
the onError callback, then await that signal before asserting refresh outcomes,
while preserving the existing onError and onAuthFailure expectations.

In `@apps/web/src/services/api/http-factory/dedupe-manager.ts`:
- Around line 19-62: 更新 DedupeManager 的 defaultGenerateKey,使去重 key 基于注入最终
headers 后的请求语义生成:使用最终 URI,纳入 paramsSerializer 处理后的参数,并保留 Date 等值的正确序列化;同时将
Authorization 和租户作用域加入 key,确保不同用户或租户的请求不会合并。调整调用时机,使其发生在请求拦截器完成身份与租户 headers
注入之后,并相应复用或更新 stableSerialize/normalizeForSerialize。

In `@apps/web/src/services/api/http-factory/index.ts`:
- Around line 53-56: Update the deduplication setup in the HTTP factory around
dedupePolicy and DedupeManager so request-level dedupePolicy values override the
client-level configuration. Resolve the effective enabled state and generateKey
from request options first, falling back to client defaults, then create
DedupeManager whenever the effective policy is enabled and use its effective key
generator.
- Around line 213-217: Update the request-header flow around headersProvider and
needToken to normalize and merge all caller/provider headers into an
AxiosHeaders instance before evaluating token requirements. Use AxiosHeaders.get
for case-insensitive detection of an existing access-token header, then only
read or refresh the local token when needed; inject it with AxiosHeaders.set so
custom authorization headers are correctly respected or overridden.

In `@apps/web/src/services/api/http-factory/reference/http-demo.ts`:
- Around line 70-73: 将 refreshFailureCodes 的中文注释限定为用于判断 refresh 请求响应是否表示 refresh
token 失效,避免将其描述为普通请求通用的鉴权失败配置;仅修改该注释,保留状态码列表不变。

In `@apps/web/src/services/api/http-factory/reference/README.md`:
- Around line 15-17: Update the README sections around the refresh-failure
documentation, including the references near lines 14, 274, 298, 315, and 320,
to match the current isRefreshFailure default behavior and tests. Remove claims
that every refresh failure invokes onAuthFailure, that missing access tokens
automatically trigger it, or that non-Error exceptions do so by default;
document the actual conditions and error propagation behavior instead.

---

Outside diff comments:
In `@apps/web/src/services/api/http-factory/index.ts`:
- Around line 71-98: Update the deduplication interception around
instance.request so it also applies to Axios alias methods such as get, delete,
head, and options, whose calls use the internal context.request. Move the GET
deduplication logic into a shared adapter/interceptor path or explicitly
override all relevant request entry points, while preserving request-level
policy overrides and non-GET bypass behavior.
🪄 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: d99d3a73-7f8e-43b3-b4c3-de7c31e8911d

📥 Commits

Reviewing files that changed from the base of the PR and between 554da17 and 9a6f04a.

📒 Files selected for processing (13)
  • apps/web/src/services/api/http-factory/__tests__/http-client.edge-cases.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.test.ts
  • apps/web/src/services/api/http-factory/__tests__/http-client.token-normalization.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/types/common.ts
  • apps/web/src/services/api/http-factory/types/http-client-options.ts
  • apps/web/src/services/api/http-factory/utils/refresh.ts
  • apps/web/src/services/api/new-http.ts

Comment thread apps/web/src/services/api/http-factory/__tests__/http-client.test.ts Outdated
Comment thread apps/web/src/services/api/http-factory/dedupe-manager.ts
Comment thread apps/web/src/services/api/http-factory/index.ts Outdated
Comment thread apps/web/src/services/api/http-factory/index.ts Outdated
Comment thread apps/web/src/services/api/http-factory/reference/http-demo.ts
Comment thread apps/web/src/services/api/http-factory/reference/README.md

@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.

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

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

接口命名不符合项目编码规范。

根据编码规范,TypeScript 接口应使用 I 前缀(如 IUser)。新增的 RequestDedupePolicy 接口缺少 I 前缀,应为 IRequestDedupePolicy。同理,axios 模块增强中引用该类型处也需同步更新。

注意到现有 DedupePolicy 接口同样未遵循此规范,但新增代码应遵守规范。

As per coding guidelines: **/*.{ts,tsx}: Use PascalCase for type and interface names, with I prefix for interfaces (e.g., IUser)

♻️ 建议的命名修正
-/**
- * 请求级合并配置。
- * 仅允许覆盖 enabled;generateKey 只能在客户端级配置。
- */
-export interface RequestDedupePolicy {
-  /** 是否启用请求合并。覆盖客户端级 enabled。 */
-  enabled?: boolean;
-}
+/**
+ * 请求级合并配置。
+ * 仅允许覆盖 enabled;generateKey 只能在客户端级配置。
+ */
+export interface IRequestDedupePolicy {
+  /** 是否启用请求合并。覆盖客户端级 enabled。 */
+  enabled?: boolean;
+}

以及同步更新 axios 模块增强:

 declare module "axios" {
   interface AxiosRequestConfig {
-    dedupePolicy?: RequestDedupePolicy;
+    dedupePolicy?: IRequestDedupePolicy;
   }
 }
🤖 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 24 - 42, 将新增接口 RequestDedupePolicy 重命名为 IRequestDedupePolicy,并同步更新
AxiosRequestConfig.dedupePolicy 的类型引用;不要修改现有 DedupePolicy 或其他无关代码。

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.

Nitpick comments:
In `@apps/web/src/services/api/http-factory/types/http-client-options.ts`:
- Around line 24-42: 将新增接口 RequestDedupePolicy 重命名为 IRequestDedupePolicy,并同步更新
AxiosRequestConfig.dedupePolicy 的类型引用;不要修改现有 DedupePolicy 或其他无关代码。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 59eaafb8-3625-4e36-a61f-41cbc910473d

📥 Commits

Reviewing files that changed from the base of the PR and between 9a6f04a and 891d72a.

📒 Files selected for processing (8)
  • apps/web/src/services/api/http-factory/__tests__/http-client.refresh.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-normalization.test.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/types/common.ts
  • apps/web/src/services/api/http-factory/types/http-client-options.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/web/src/services/api/http-factory/tests/http-client.token-normalization.test.ts
  • apps/web/src/services/api/http-factory/reference/http-demo.ts
  • apps/web/src/services/api/http-factory/tests/http-client.refresh.test.ts
  • apps/web/src/services/api/http-factory/reference/README.md
  • apps/web/src/services/api/http-factory/index.ts
  • apps/web/src/services/api/http-factory/tests/http-client.test.ts

@fengzai6

fengzai6 commented Jul 13, 2026

Copy link
Copy Markdown
Owner Author

🧹 Nitpick comments (1)

apps/web/src/services/api/http-factory/types/http-client-options.ts (1)> 24-42: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

接口命名不符合项目编码规范。
根据编码规范,TypeScript 接口应使用 I 前缀(如 IUser)。新增的 RequestDedupePolicy 接口缺少 I 前缀,应为 IRequestDedupePolicy。同理,axios 模块增强中引用该类型处也需同步更新。
注意到现有 DedupePolicy 接口同样未遵循此规范,但新增代码应遵守规范。
As per coding guidelines: **/*.{ts,tsx}: Use PascalCase for type and interface names, with I prefix for interfaces (e.g., IUser)

♻️ 建议的命名修正

-/**
- * 请求级合并配置。
- * 仅允许覆盖 enabled;generateKey 只能在客户端级配置。
- */
-export interface RequestDedupePolicy {
-  /** 是否启用请求合并。覆盖客户端级 enabled。 */
-  enabled?: boolean;
-}
+/**
+ * 请求级合并配置。
+ * 仅允许覆盖 enabled;generateKey 只能在客户端级配置。
+ */
+export interface IRequestDedupePolicy {
+  /** 是否启用请求合并。覆盖客户端级 enabled。 */
+  enabled?: boolean;
+}

以及同步更新 axios 模块增强:

 declare module "axios" {
   interface AxiosRequestConfig {
-    dedupePolicy?: RequestDedupePolicy;
+    dedupePolicy?: IRequestDedupePolicy;
   }
 }

🤖 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 24 - 42, 将新增接口 RequestDedupePolicy 重命名为 IRequestDedupePolicy,并同步更新
AxiosRequestConfig.dedupePolicy 的类型引用;不要修改现有 DedupePolicy 或其他无关代码。

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.

Nitpick comments:
In `@apps/web/src/services/api/http-factory/types/http-client-options.ts`:
- Around line 24-42: 将新增接口 RequestDedupePolicy 重命名为 IRequestDedupePolicy,并同步更新
AxiosRequestConfig.dedupePolicy 的类型引用;不要修改现有 DedupePolicy 或其他无关代码。

ℹ️ Review info

@coderabbitai 忽视该问题

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@fengzai6 好的,已忽略该建议,不会再对此提出异议。

@fengzai6

Copy link
Copy Markdown
Owner Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Comments resolved and changes approved.

@fengzai6
fengzai6 merged commit 2c5efc3 into main Jul 13, 2026
4 checks passed
@fengzai6
fengzai6 deleted the fix/http-factory-review-p0-p1 branch July 13, 2026 07:49
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