Skip to content

feat(docs): GET /api/docs/resolve 路径解析端点#38

Merged
longsizhuo merged 1 commit into
mainfrom
feat/docs-resolve
May 24, 2026
Merged

feat(docs): GET /api/docs/resolve 路径解析端点#38
longsizhuo merged 1 commit into
mainfrom
feat/docs-resolve

Conversation

@longsizhuo
Copy link
Copy Markdown
Member

背景

生产 /zh/docs/community/*(带 locale 前缀的旧路径)已 404,需要后端提供路径解析端点供前端 Block 3 使用。

新增内容

DocPathService

  • normalize(path):strip /zh|en/ locale 前缀、去 fragment(#)、去尾斜杠
  • resolveCanonical(inputPath):UNION 查询 docs.path_current(前缀 content/)和 doc_paths.path(前缀 app/),返回 canonical /docs/... 路径
  • @Cacheable("doc-resolve"):key = normalize 后的路径,保证 /zh/docs/.../docs/... 命中同一缓存条目

DocsResolveController

GET /api/docs/resolve?path=/zh/docs/community/dev-tips/git101
→ 301 Location: /docs/community/dev-tips/git101
→ 404(路径不认识)

canonical 不带 locale,前端 Block 3 负责拼 locale 后再做最终跳转。

配置变更

  • SaTokenConfigure:加 .notMatch("/api/docs/resolve") 白名单
  • application.propertiesspring.cache.cache-namesdoc-resolve

Smoke test 结果(本地 8081)

输入 HTTP Location
/zh/docs/community/dev-tips/git101 301 /docs/community/dev-tips/git101
/docs/community/dev-tips/git101 301 /docs/community/dev-tips/git101
/en/docs/community/dev-tips/git101 301 /docs/community/dev-tips/git101
/docs/nonexistent/page 404
无 satoken token 301 /docs/community/dev-tips/git101

新增 DocPathService + DocsResolveController,将任意输入路径
(含 /zh|en/ locale 前缀、历史重命名路径)解析为 canonical URL。

- normalize():strip locale 前缀、去 fragment、去尾斜杠
- SQL UNION:docs.path_current(前缀 content/)+ doc_paths.path(前缀 app/)
- @Cacheable("doc-resolve"):key = normalize 后的路径,避免 /zh/ 和 /docs/ 重复缓存
- SaTokenConfigure 白名单加 /api/docs/resolve
- application.properties cache-names 加 doc-resolve

Smoke test 通过:
  /zh/docs/community/dev-tips/git101 → 301 /docs/community/dev-tips/git101
  /docs/nonexistent/page             → 404
  无 satoken                         → 301(不是 401)
Copilot AI review requested due to automatic review settings May 24, 2026 17:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

该 PR 为前端 Block 3 增加一个“文档路径解析”能力:将带 locale 前缀的旧路径(如 /zh/docs/...)解析为不带 locale 的 canonical /docs/...,并通过后端 301 重定向输出,解决生产旧路径 404 的问题。

Changes:

  • 新增 DocPathService:规范化输入路径并从 docs/doc_paths 查询 canonical /docs/...,并使用 Caffeine 缓存。
  • 新增 GET /api/docs/resolve 端点:命中则返回 301 Location,未命中返回 404。
  • 配置变更:加入 Sa-Token 白名单、注册新增 cache name。

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
src/main/resources/application.properties 注册新增的 doc-resolve 缓存名
src/main/java/com/involutionhell/backend/docs/service/DocPathService.java 新增路径规范化 + DB 查询 + 缓存的解析服务
src/main/java/com/involutionhell/backend/docs/controller/DocsResolveController.java 新增公开解析端点并返回 301/404
src/main/java/com/involutionhell/backend/common/config/SaTokenConfigure.java /api/docs/resolve 加入 Sa-Token 白名单

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +70 to +75
// docs.path_current 前缀是 content/,doc_paths.path 前缀是 app/
String sql = """
SELECT canonical_path FROM (
SELECT regexp_replace(
regexp_replace(d.path_current, '^content', ''),
'(/index)?\\.(mdx|md)$', ''
Comment on lines +36 to +45
String normalize(String path) {
if (path == null) return null;
// 去 fragment
int h = path.indexOf('#');
if (h >= 0) path = path.substring(0, h);
// strip locale 前缀 /zh/ 或 /en/
path = path.replaceFirst("^/(zh|en)/", "/");
// 去尾斜杠(根路径 "/" 不动)
if (path.length() > 1 && path.endsWith("/")) {
path = path.substring(0, path.length() - 1);
Comment on lines +63 to +68
@Cacheable(value = "doc-resolve", key = "T(com.involutionhell.backend.docs.service.DocPathService).normalizeStatic(#inputPath)")
public Optional<String> resolveCanonical(String inputPath) {
String normalizedPath = normalize(inputPath);
if (normalizedPath == null || normalizedPath.isBlank()) {
return Optional.empty();
}
# 注册所有需要的缓存名(之前写了两次被覆盖,eventSummary 实际没注册导致缓存失效)
# docHistory 用来缓存 GitHub commits API 结果,避免给每次文档页访问都打 GitHub 限流
spring.cache.cache-names=topDocs,eventSummary,docHistory,githubRepos,zoteroItems,leaderboard
spring.cache.cache-names=topDocs,eventSummary,docHistory,githubRepos,zoteroItems,leaderboard,doc-resolve
Comment on lines +32 to +40
@GetMapping("/api/docs/resolve")
public ResponseEntity<Void> resolve(@RequestParam String path) {
Optional<String> canonical = docPathService.resolveCanonical(path);
if (canonical.isPresent()) {
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY)
.location(URI.create(canonical.get()))
.build();
}
return ResponseEntity.notFound().build();
@longsizhuo longsizhuo merged commit d941eb6 into main May 24, 2026
1 check passed
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.

2 participants