@sansenjian/qq-music-api 2.2.9 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/CHANGELOG.md +28 -1
  2. package/README.md +10 -11
  3. package/dist/api/index.js +9 -0
  4. package/dist/app.js +8 -43
  5. package/dist/index.js +13 -1
  6. package/dist/koaApp.js +49 -0
  7. package/dist/module/apis/downloadQQMusic.js +2 -1
  8. package/dist/module/apis/music/getLyric.js +220 -16
  9. package/dist/module/apis/music/getMusicPlay.js +3 -2
  10. package/dist/package.json +19 -15
  11. package/dist/routers/context/getLyric.js +12 -2
  12. package/dist/routers/context/getNewDisks.js +4 -0
  13. package/dist/routers/context/getRecommend.js +4 -0
  14. package/dist/routers/context/getTicketInfo.js +4 -0
  15. package/dist/util/cookieResolver.js +10 -4
  16. package/docs-dist/404.html +6 -6
  17. package/docs-dist/CHANGELOG-ARCHITECTURE.html +14 -14
  18. package/docs-dist/COOKIE_CONFIG_GUIDE.html +13 -13
  19. package/docs-dist/DEGRADE_EXAMPLES.html +109 -0
  20. package/docs-dist/FALLBACK_MODE_GUIDE.html +21 -21
  21. package/docs-dist/QUICK_START.html +62 -0
  22. package/docs-dist/README.html +17 -17
  23. package/docs-dist/TEST_USER_PLAYLISTS.html +14 -14
  24. package/docs-dist/USER_AVATAR_GUIDE.html +16 -16
  25. package/docs-dist/api/comments.html +12 -12
  26. package/docs-dist/api/index.html +10 -10
  27. package/docs-dist/api/music.html +15 -13
  28. package/docs-dist/api/other.html +13 -13
  29. package/docs-dist/api/playground.html +27 -0
  30. package/docs-dist/api/playlist.html +15 -15
  31. package/docs-dist/api/rank.html +12 -12
  32. package/docs-dist/api/search.html +13 -13
  33. package/docs-dist/api/singer.html +12 -12
  34. package/docs-dist/api/user.html +16 -16
  35. package/docs-dist/assets/{CHANGELOG-ARCHITECTURE.md.r40JGJZK.js → CHANGELOG-ARCHITECTURE.md.CYHmaBdY.js} +5 -5
  36. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.CYHmaBdY.lean.js +1 -0
  37. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.Nvywo7CW.js +13 -0
  38. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.Nvywo7CW.lean.js +1 -0
  39. package/docs-dist/assets/DEGRADE_EXAMPLES.md.Cz2J-qwE.js +83 -0
  40. package/docs-dist/assets/DEGRADE_EXAMPLES.md.Cz2J-qwE.lean.js +1 -0
  41. package/docs-dist/assets/{FALLBACK_MODE_GUIDE.md.BBdcIdh_.js → FALLBACK_MODE_GUIDE.md.wKA9yqoI.js} +12 -12
  42. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.wKA9yqoI.lean.js +1 -0
  43. package/docs-dist/assets/QUICK_START.md.D5KfDgbs.js +36 -0
  44. package/docs-dist/assets/QUICK_START.md.D5KfDgbs.lean.js +1 -0
  45. package/docs-dist/assets/README.md.CHbArqA7.js +421 -0
  46. package/docs-dist/assets/README.md.CHbArqA7.lean.js +1 -0
  47. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.BfBxYbaM.js +16 -0
  48. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.BfBxYbaM.lean.js +1 -0
  49. package/docs-dist/assets/{USER_AVATAR_GUIDE.md.CVHPs2Dn.js → USER_AVATAR_GUIDE.md.D5Rti1Gg.js} +7 -7
  50. package/docs-dist/assets/USER_AVATAR_GUIDE.md.D5Rti1Gg.lean.js +1 -0
  51. package/docs-dist/assets/{api_comments.md.79Q_C8Qp.js → api_comments.md.5nDhrWa8.js} +3 -3
  52. package/docs-dist/assets/api_comments.md.5nDhrWa8.lean.js +1 -0
  53. package/docs-dist/assets/api_index.md.DdG1WHkZ.js +1 -0
  54. package/docs-dist/assets/api_index.md.DdG1WHkZ.lean.js +1 -0
  55. package/docs-dist/assets/{api_music.md.B1AzLePX.js → api_music.md.D66hq-_4.js} +6 -4
  56. package/docs-dist/assets/api_music.md.D66hq-_4.lean.js +1 -0
  57. package/docs-dist/assets/api_other.md.9KhspVEM.js +7 -0
  58. package/docs-dist/assets/api_other.md.9KhspVEM.lean.js +1 -0
  59. package/docs-dist/assets/api_playground.md.BZBvYMm2.js +11 -0
  60. package/docs-dist/assets/api_playground.md.BZBvYMm2.lean.js +11 -0
  61. package/docs-dist/assets/{api_playlist.md.8ACJ3QqD.js → api_playlist.md.BQK32ZyE.js} +6 -6
  62. package/docs-dist/assets/api_playlist.md.BQK32ZyE.lean.js +1 -0
  63. package/docs-dist/assets/{api_rank.md.B8IP2ZRy.js → api_rank.md.z7YBwVgw.js} +3 -3
  64. package/docs-dist/assets/api_rank.md.z7YBwVgw.lean.js +1 -0
  65. package/docs-dist/assets/{api_search.md.DO9J6nvp.js → api_search.md.GfzIBRfc.js} +4 -4
  66. package/docs-dist/assets/api_search.md.GfzIBRfc.lean.js +1 -0
  67. package/docs-dist/assets/api_singer.md.BDR-_qDH.js +21 -0
  68. package/docs-dist/assets/api_singer.md.BDR-_qDH.lean.js +1 -0
  69. package/docs-dist/assets/{api_user.md.Cb7Ky3Sn.js → api_user.md.Dx8BWGrb.js} +7 -7
  70. package/docs-dist/assets/api_user.md.Dx8BWGrb.lean.js +1 -0
  71. package/docs-dist/assets/app.CxuIZ1W7.js +1 -0
  72. package/docs-dist/assets/chunks/@localSearchIndexroot.ygoKgu27.js +1 -0
  73. package/docs-dist/assets/chunks/VPLocalSearchBox.BqgkAhNM.js +3 -0
  74. package/docs-dist/assets/chunks/framework.BUY3a635.js +4 -0
  75. package/docs-dist/assets/chunks/theme.C-Z3DN0r.js +2 -0
  76. package/docs-dist/assets/{guide_architecture.md.CzgqynmB.js → guide_architecture.md.SHnKkzwb.js} +20 -20
  77. package/docs-dist/assets/guide_architecture.md.SHnKkzwb.lean.js +1 -0
  78. package/docs-dist/assets/guide_authentication.md.CZCKocgR.js +4 -0
  79. package/docs-dist/assets/guide_authentication.md.CZCKocgR.lean.js +1 -0
  80. package/docs-dist/assets/guide_index.md.CkJ-jjL0.js +1 -0
  81. package/docs-dist/assets/guide_index.md.CkJ-jjL0.lean.js +1 -0
  82. package/docs-dist/assets/guide_installation.md.D2TBzILh.js +7 -0
  83. package/docs-dist/assets/guide_installation.md.D2TBzILh.lean.js +1 -0
  84. package/docs-dist/assets/guide_quickstart.md.J7Sib8wg.js +13 -0
  85. package/docs-dist/assets/guide_quickstart.md.J7Sib8wg.lean.js +1 -0
  86. package/docs-dist/assets/index.md.ClwYf6Qc.js +1 -0
  87. package/docs-dist/assets/index.md.ClwYf6Qc.lean.js +1 -0
  88. package/docs-dist/assets/inter-italic-cyrillic-ext._dlW9xFb.woff2 +0 -0
  89. package/docs-dist/assets/inter-italic-cyrillic.D7dRslh9.woff2 +0 -0
  90. package/docs-dist/assets/inter-italic-greek-ext.Ct-Tf2bq.woff2 +0 -0
  91. package/docs-dist/assets/inter-italic-greek.DNcpQ8QC.woff2 +0 -0
  92. package/docs-dist/assets/inter-italic-latin-ext.DytegdRQ.woff2 +0 -0
  93. package/docs-dist/assets/inter-italic-latin.COaG5lWR.woff2 +0 -0
  94. package/docs-dist/assets/inter-italic-vietnamese.BI5UxJD-.woff2 +0 -0
  95. package/docs-dist/assets/inter-roman-cyrillic-ext.BeNbU08G.woff2 +0 -0
  96. package/docs-dist/assets/inter-roman-cyrillic.CD0kT8R4.woff2 +0 -0
  97. package/docs-dist/assets/inter-roman-greek-ext.CFAEQ5Ow.woff2 +0 -0
  98. package/docs-dist/assets/inter-roman-greek.Dsf7YjP7.woff2 +0 -0
  99. package/docs-dist/assets/inter-roman-latin-ext.Dl_ayf4-.woff2 +0 -0
  100. package/docs-dist/assets/inter-roman-latin.Cy4MYw_J.woff2 +0 -0
  101. package/docs-dist/assets/inter-roman-vietnamese.CpqCnS2H.woff2 +0 -0
  102. package/docs-dist/assets/reference_response-format.md.BrGoGoPV.js +12 -0
  103. package/docs-dist/assets/reference_response-format.md.BrGoGoPV.lean.js +1 -0
  104. package/docs-dist/assets/style.D_YoXH3a.css +1 -0
  105. package/docs-dist/guide/architecture.html +29 -29
  106. package/docs-dist/guide/authentication.html +12 -12
  107. package/docs-dist/guide/index.html +10 -10
  108. package/docs-dist/guide/installation.html +13 -13
  109. package/docs-dist/guide/quickstart.html +15 -15
  110. package/docs-dist/hashmap.json +1 -1
  111. package/docs-dist/index.html +10 -10
  112. package/docs-dist/reference/response-format.html +13 -13
  113. package/docs-dist/version.json +3 -3
  114. package/package.json +19 -15
  115. package/public/index.html +966 -0
  116. package/public/playground-utils.js +150 -0
  117. package/dist/jest.config.js +0 -52
  118. package/dist/scripts/run-tests-with-flags.js +0 -139
  119. package/dist/types/api.js +0 -55
  120. package/docs-dist/assets/CHANGELOG-ARCHITECTURE.md.r40JGJZK.lean.js +0 -1
  121. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.BVXl7WHu.js +0 -13
  122. package/docs-dist/assets/COOKIE_CONFIG_GUIDE.md.BVXl7WHu.lean.js +0 -1
  123. package/docs-dist/assets/FALLBACK_MODE_GUIDE.md.BBdcIdh_.lean.js +0 -1
  124. package/docs-dist/assets/README.md.D6Tw0nRd.js +0 -421
  125. package/docs-dist/assets/README.md.D6Tw0nRd.lean.js +0 -1
  126. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.DSt20Igj.js +0 -16
  127. package/docs-dist/assets/TEST_USER_PLAYLISTS.md.DSt20Igj.lean.js +0 -1
  128. package/docs-dist/assets/USER_AVATAR_GUIDE.md.CVHPs2Dn.lean.js +0 -1
  129. package/docs-dist/assets/api_comments.md.79Q_C8Qp.lean.js +0 -1
  130. package/docs-dist/assets/api_index.md.CU3By8tw.js +0 -1
  131. package/docs-dist/assets/api_index.md.CU3By8tw.lean.js +0 -1
  132. package/docs-dist/assets/api_music.md.B1AzLePX.lean.js +0 -1
  133. package/docs-dist/assets/api_other.md.DCg4bzA7.js +0 -7
  134. package/docs-dist/assets/api_other.md.DCg4bzA7.lean.js +0 -1
  135. package/docs-dist/assets/api_playlist.md.8ACJ3QqD.lean.js +0 -1
  136. package/docs-dist/assets/api_rank.md.B8IP2ZRy.lean.js +0 -1
  137. package/docs-dist/assets/api_search.md.DO9J6nvp.lean.js +0 -1
  138. package/docs-dist/assets/api_singer.md.CcL32xuN.js +0 -21
  139. package/docs-dist/assets/api_singer.md.CcL32xuN.lean.js +0 -1
  140. package/docs-dist/assets/api_user.md.Cb7Ky3Sn.lean.js +0 -1
  141. package/docs-dist/assets/app.CSainqD9.js +0 -1
  142. package/docs-dist/assets/chunks/@localSearchIndexroot.BKleDIv-.js +0 -1
  143. package/docs-dist/assets/chunks/VPLocalSearchBox.BUBaq7tw.js +0 -9
  144. package/docs-dist/assets/chunks/framework.aJbMEiY9.js +0 -19
  145. package/docs-dist/assets/chunks/theme.CzMhU0Ps.js +0 -2
  146. package/docs-dist/assets/guide_architecture.md.CzgqynmB.lean.js +0 -1
  147. package/docs-dist/assets/guide_authentication.md.a8yTA8Xe.js +0 -4
  148. package/docs-dist/assets/guide_authentication.md.a8yTA8Xe.lean.js +0 -1
  149. package/docs-dist/assets/guide_index.md.BgUUL6fI.js +0 -1
  150. package/docs-dist/assets/guide_index.md.BgUUL6fI.lean.js +0 -1
  151. package/docs-dist/assets/guide_installation.md.BCZ4jBl_.js +0 -7
  152. package/docs-dist/assets/guide_installation.md.BCZ4jBl_.lean.js +0 -1
  153. package/docs-dist/assets/guide_quickstart.md.9-4dA6wS.js +0 -13
  154. package/docs-dist/assets/guide_quickstart.md.9-4dA6wS.lean.js +0 -1
  155. package/docs-dist/assets/index.md.z0hAJioN.js +0 -1
  156. package/docs-dist/assets/index.md.z0hAJioN.lean.js +0 -1
  157. package/docs-dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  158. package/docs-dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  159. package/docs-dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  160. package/docs-dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  161. package/docs-dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  162. package/docs-dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  163. package/docs-dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  164. package/docs-dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  165. package/docs-dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  166. package/docs-dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  167. package/docs-dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  168. package/docs-dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  169. package/docs-dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  170. package/docs-dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  171. package/docs-dist/assets/reference_response-format.md.VvQTLDZr.js +0 -12
  172. package/docs-dist/assets/reference_response-format.md.VvQTLDZr.lean.js +0 -1
  173. package/docs-dist/assets/style.DM4qKDd4.css +0 -1
@@ -1,26 +1,26 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en-US" dir="ltr">
2
+ <html lang="zh-CN" dir="ltr">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1">
6
6
  <title>代码架构说明 | QQ Music API</title>
7
7
  <meta name="description" content="QQ 音乐 API 接口文档">
8
- <meta name="generator" content="VitePress v1.6.4">
9
- <link rel="preload stylesheet" href="/qq-music-api/assets/style.DM4qKDd4.css" as="style">
8
+ <meta name="generator" content="VitePress v2.0.0-alpha.17">
9
+ <link rel="preload stylesheet" href="/qq-music-api/assets/style.D_YoXH3a.css" as="style">
10
10
  <link rel="preload stylesheet" href="/qq-music-api/vp-icons.css" as="style">
11
11
 
12
- <script type="module" src="/qq-music-api/assets/app.CSainqD9.js"></script>
13
- <link rel="preload" href="/qq-music-api/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
- <link rel="modulepreload" href="/qq-music-api/assets/chunks/theme.CzMhU0Ps.js">
15
- <link rel="modulepreload" href="/qq-music-api/assets/chunks/framework.aJbMEiY9.js">
16
- <link rel="modulepreload" href="/qq-music-api/assets/guide_architecture.md.CzgqynmB.lean.js">
12
+ <script type="module" src="/qq-music-api/assets/app.CxuIZ1W7.js"></script>
13
+ <link rel="preload" href="/qq-music-api/assets/inter-roman-latin.Cy4MYw_J.woff2" as="font" type="font/woff2" crossorigin="">
14
+ <link rel="modulepreload" href="/qq-music-api/assets/chunks/theme.C-Z3DN0r.js">
15
+ <link rel="modulepreload" href="/qq-music-api/assets/chunks/framework.BUY3a635.js">
16
+ <link rel="modulepreload" href="/qq-music-api/assets/guide_architecture.md.SHnKkzwb.lean.js">
17
17
  <link rel="icon" href="/logo.svg">
18
18
  <meta name="theme-color" content="#12b7f5">
19
19
  <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
20
20
  <script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
21
21
  </head>
22
22
  <body>
23
- <div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0b0ada53></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0b0ada53>Skip to content</a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar" data-v-ae24b3ad data-v-6aa21345><div class="wrapper" data-v-6aa21345><div class="container" data-v-6aa21345><div class="title" data-v-6aa21345><div class="VPNavBarTitle has-sidebar" data-v-6aa21345 data-v-1168a8e4><a class="title" href="/qq-music-api/" data-v-1168a8e4><!--[--><!--]--><!--[--><img class="VPImage logo" src="/qq-music-api/logo.svg" alt data-v-8426fc1a><!--]--><span data-v-1168a8e4>QQ Music API</span><!--[--><!--]--></a></div></div><div class="content" data-v-6aa21345><div class="content-body" data-v-6aa21345><!--[--><!--]--><div class="VPNavBarSearch search" data-v-6aa21345><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="搜索文档"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">搜索</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-6aa21345 data-v-dc692963><span id="main-nav-aria-label" class="visually-hidden" data-v-dc692963> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/guide/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>使用指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/api/" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>API 文档</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/api/user.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>用户能力</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink active" href="/qq-music-api/guide/architecture.html" tabindex="0" data-v-dc692963 data-v-e56f3d57><!--[--><span data-v-e56f3d57>架构说明</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-6aa21345 data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-6aa21345 data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/sansenjian/qq-music-api" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-bd121fe5><span class="vpi-social-github"></span></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-6aa21345 data-v-bb2aa2f0 data-v-cf11d7a2><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-cf11d7a2><span class="vpi-more-horizontal icon" data-v-cf11d7a2></span></button><div class="menu" data-v-cf11d7a2><div class="VPMenu" data-v-cf11d7a2 data-v-b98bc113><!----><!--[--><!--[--><!----><div class="group" data-v-bb2aa2f0><div class="item appearance" data-v-bb2aa2f0><p class="label" data-v-bb2aa2f0>Appearance</p><div class="appearance-action" data-v-bb2aa2f0><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-bb2aa2f0 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><div class="group" data-v-bb2aa2f0><div class="item social-links" data-v-bb2aa2f0><div class="VPSocialLinks social-links-list" data-v-bb2aa2f0 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/sansenjian/qq-music-api" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-bd121fe5><span class="vpi-social-github"></span></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-6aa21345 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-6aa21345><div class="divider-line" data-v-6aa21345></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-5d98c3a5 data-v-a6f0e41e><div class="container" data-v-a6f0e41e><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-a6f0e41e><span class="vpi-align-left menu-icon" data-v-a6f0e41e></span><span class="menu-text" data-v-a6f0e41e>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-a6f0e41e data-v-8a42e2b4><button data-v-8a42e2b4>Return to top</button><!----></div></div></div><aside class="VPSidebar" data-v-5d98c3a5 data-v-319d5ca6><div class="curtain" data-v-319d5ca6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-319d5ca6><span class="visually-hidden" id="sidebar-aria-label" data-v-319d5ca6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-c40bc020><section class="VPSidebarItem level-0" data-v-c40bc020 data-v-b3fd67f8><div class="item" role="button" tabindex="0" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><h2 class="text" data-v-b3fd67f8>开始使用</h2><!----></div><div class="items" data-v-b3fd67f8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>首页</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/guide/" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>使用指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/guide/installation.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>安装指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/guide/quickstart.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>快速开始</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-c40bc020><section class="VPSidebarItem level-0" data-v-c40bc020 data-v-b3fd67f8><div class="item" role="button" tabindex="0" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><h2 class="text" data-v-b3fd67f8>认证与用户</h2><!----></div><div class="items" data-v-b3fd67f8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/guide/authentication.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>认证与登录</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/user.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>用户接口</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-c40bc020><section class="VPSidebarItem level-0" data-v-c40bc020 data-v-b3fd67f8><div class="item" role="button" tabindex="0" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><h2 class="text" data-v-b3fd67f8>API 文档</h2><!----></div><div class="items" data-v-b3fd67f8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>API 总览</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/music.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>音乐相关</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/singer.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>歌手相关</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/playlist.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>歌单相关</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/rank.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>排行榜</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/search.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>搜索</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/comments.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>评论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/api/other.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>其他接口</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-c40bc020><section class="VPSidebarItem level-0 has-active" data-v-c40bc020 data-v-b3fd67f8><div class="item" role="button" tabindex="0" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><h2 class="text" data-v-b3fd67f8>开发与维护</h2><!----></div><div class="items" data-v-b3fd67f8><!--[--><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/reference/response-format.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>响应格式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-b3fd67f8 data-v-b3fd67f8><div class="item" data-v-b3fd67f8><div class="indicator" data-v-b3fd67f8></div><a class="VPLink link link" href="/qq-music-api/guide/architecture.html" data-v-b3fd67f8><!--[--><p class="text" data-v-b3fd67f8>代码架构</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-5d98c3a5 data-v-1428d186><div class="VPDoc has-sidebar has-aside" data-v-1428d186 data-v-39a288b8><!--[--><!--]--><div class="container" data-v-39a288b8><div class="aside" data-v-39a288b8><div class="aside-curtain" data-v-39a288b8></div><div class="aside-container" data-v-39a288b8><div class="aside-content" data-v-39a288b8><div class="VPDocAside" data-v-39a288b8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-a5bbad30><div class="content" data-v-a5bbad30><div class="outline-marker" data-v-a5bbad30></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-a5bbad30>On this page</div><ul class="VPDocOutlineItem root" data-v-a5bbad30 data-v-b933a997><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-39a288b8><div class="content-container" data-v-39a288b8><!--[--><!--]--><main class="main" data-v-39a288b8><div style="position:relative;" class="vp-doc _qq-music-api_guide_architecture" data-v-39a288b8><div><h1 id="代码架构说明" tabindex="-1">代码架构说明 <a class="header-anchor" href="#代码架构说明" aria-label="Permalink to &quot;代码架构说明&quot;">​</a></h1><p>本文档介绍项目的代码架构和抽象设计。</p><h2 id="代码抽象" tabindex="-1">代码抽象 <a class="header-anchor" href="#代码抽象" aria-label="Permalink to &quot;代码抽象&quot;">​</a></h2><p>为了提高代码的可维护性和开发效率,项目进行了以下代码抽象:</p><h3 id="_1-统一的-api-类型定义" tabindex="-1">1. 统一的 API 类型定义 <a class="header-anchor" href="#_1-统一的-api-类型定义" aria-label="Permalink to &quot;1. 统一的 API 类型定义&quot;">​</a></h3><p><strong>文件位置</strong>: <a href="../../types/api.ts"><code>types/api.ts</code></a></p><p>定义了项目中所有 API 函数使用的通用类型:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// API 响应结构</span></span>
23
+ <div id="app"><div class="Layout" data-v-0cf61682><!--[--><!--]--><!--[--><span tabindex="-1" data-v-331ec75c></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-331ec75c>跳转到内容</a><!--]--><!----><header class="VPNav" data-v-0cf61682 data-v-9f75dce3><div class="VPNavBar has-sidebar top" data-v-9f75dce3 data-v-9ca1369d><div class="wrapper" data-v-9ca1369d><div class="container" data-v-9ca1369d><div class="title" data-v-9ca1369d><div class="VPNavBarTitle has-sidebar" data-v-9ca1369d data-v-1e38c6bc><a class="title" href="/qq-music-api/" data-v-1e38c6bc><!--[--><!--]--><!--[--><img class="VPImage logo" src="/qq-music-api/logo.svg" alt data-v-8426fc1a><!--]--><span data-v-1e38c6bc>QQ Music API</span><!--[--><!--]--></a></div></div><div class="content" data-v-9ca1369d><div class="content-body" data-v-9ca1369d><!--[--><!--]--><div class="VPNavBarSearch search" data-v-9ca1369d data-v-2fc7f2c6><!--[--><button type="button" class="VPNavBarSearchButton" aria-label="搜索文档" aria-keyshortcuts="/ control+k meta+k" data-v-2fc7f2c6 data-v-baa3be99><span class="vpi-search" aria-hidden="true" data-v-baa3be99></span><span class="text" data-v-baa3be99>搜索</span><span class="keys" aria-hidden="true" data-v-baa3be99><kbd class="key-cmd" data-v-baa3be99>⌘</kbd><kbd class="key-ctrl" data-v-baa3be99>Ctrl</kbd><kbd data-v-baa3be99>K</kbd></span></button><!----><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-9ca1369d data-v-39714824><span id="main-nav-aria-label" class="visually-hidden" data-v-39714824> Main Navigation </span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/" tabindex="0" data-v-39714824 data-v-6dd25bb8><!--[--><span data-v-6dd25bb8>首页</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/guide/" tabindex="0" data-v-39714824 data-v-6dd25bb8><!--[--><span data-v-6dd25bb8>使用指南</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/api/" tabindex="0" data-v-39714824 data-v-6dd25bb8><!--[--><span data-v-6dd25bb8>API 文档</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/api/playground.html" tabindex="0" data-v-39714824 data-v-6dd25bb8><!--[--><span data-v-6dd25bb8>API 调试台</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/qq-music-api/api/user.html" tabindex="0" data-v-39714824 data-v-6dd25bb8><!--[--><span data-v-6dd25bb8>用户能力</span><!--]--></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink active" href="/qq-music-api/guide/architecture.html" tabindex="0" data-v-39714824 data-v-6dd25bb8><!--[--><span data-v-6dd25bb8>架构说明</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-9ca1369d data-v-6c893767><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-6c893767 data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-9ca1369d data-v-0394ad82 data-v-d07f11e6><!--[--><a class="VPSocialLink no-icon" href="https://github.com/sansenjian/qq-music-api" aria-label="github" target="_blank" rel="me noopener" data-v-d07f11e6 data-v-591a6b30><span class="vpi-social-github"></span></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-9ca1369d data-v-562c832a data-v-42cb505d><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-42cb505d><span class="vpi-more-horizontal icon" data-v-42cb505d></span></button><div class="menu" data-v-42cb505d><div class="VPMenu" data-v-42cb505d data-v-25a6cce8><!----><!--[--><!--[--><!----><div class="group" data-v-562c832a><div class="item appearance" data-v-562c832a><p class="label" data-v-562c832a>主题</p><div class="appearance-action" data-v-562c832a><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title aria-checked="false" data-v-562c832a data-v-5337faa4 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-5337faa4></span><span class="vpi-moon moon" data-v-5337faa4></span><!--]--></span></span></button></div></div></div><div class="group" data-v-562c832a><div class="item social-links" data-v-562c832a><div class="VPSocialLinks social-links-list" data-v-562c832a data-v-d07f11e6><!--[--><a class="VPSocialLink no-icon" href="https://github.com/sansenjian/qq-music-api" aria-label="github" target="_blank" rel="me noopener" data-v-d07f11e6 data-v-591a6b30><span class="vpi-social-github"></span></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-9ca1369d data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><div class="divider" data-v-9ca1369d><div class="divider-line" data-v-9ca1369d></div></div></div><!----></header><div class="VPLocalNav has-sidebar empty" data-v-0cf61682 data-v-db738f89><div class="container" data-v-db738f89><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-db738f89><span class="vpi-align-left menu-icon" data-v-db738f89></span><span class="menu-text" data-v-db738f89>菜单</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-db738f89 data-v-0bf0e06f><button data-v-0bf0e06f>返回顶部</button><!----></div></div></div><aside class="VPSidebar" data-v-0cf61682 data-v-af661f50><div class="curtain" data-v-af661f50></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-af661f50><span class="visually-hidden" id="sidebar-aria-label" data-v-af661f50> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="no-transition group" data-v-8d50c081><section class="VPSidebarItem level-0" data-v-8d50c081 data-v-d81de50c><div class="item" role="button" tabindex="0" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><h2 class="text" data-v-d81de50c>开始使用</h2><!----></div><div class="items" data-v-d81de50c><!--[--><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>首页</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/guide/" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>使用指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/guide/installation.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>安装指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/guide/quickstart.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>快速开始</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/QUICK_START.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>快速使用指南</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/DEGRADE_EXAMPLES.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>降级服务示例</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-8d50c081><section class="VPSidebarItem level-0" data-v-8d50c081 data-v-d81de50c><div class="item" role="button" tabindex="0" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><h2 class="text" data-v-d81de50c>认证与用户</h2><!----></div><div class="items" data-v-d81de50c><!--[--><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/guide/authentication.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>认证与登录</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/user.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>用户接口</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-8d50c081><section class="VPSidebarItem level-0" data-v-8d50c081 data-v-d81de50c><div class="item" role="button" tabindex="0" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><h2 class="text" data-v-d81de50c>API 文档</h2><!----></div><div class="items" data-v-d81de50c><!--[--><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>API 总览</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/music.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>音乐相关</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/singer.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>歌手相关</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/playlist.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>歌单相关</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/rank.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>排行榜</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/search.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>搜索</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/comments.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>评论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/other.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>其他接口</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/api/playground.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>API 调试台</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="no-transition group" data-v-8d50c081><section class="VPSidebarItem level-0 has-active" data-v-8d50c081 data-v-d81de50c><div class="item" role="button" tabindex="0" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><h2 class="text" data-v-d81de50c>开发与维护</h2><!----></div><div class="items" data-v-d81de50c><!--[--><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/reference/response-format.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>响应格式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-d81de50c data-v-d81de50c><div class="item" data-v-d81de50c><div class="indicator" data-v-d81de50c></div><a class="VPLink link link" href="/qq-music-api/guide/architecture.html" data-v-d81de50c><!--[--><p class="text" data-v-d81de50c>代码架构</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-0cf61682 data-v-9dc86fcc><div class="VPDoc has-sidebar has-aside" data-v-9dc86fcc data-v-7011f0d8><!--[--><!--]--><div class="container" data-v-7011f0d8><div class="aside" data-v-7011f0d8><div class="aside-curtain" data-v-7011f0d8></div><div class="aside-container" data-v-7011f0d8><div class="aside-content" data-v-7011f0d8><div class="VPDocAside" data-v-7011f0d8 data-v-3f215769><!--[--><!--]--><!--[--><!--]--><nav aria-labelledby="doc-outline-aria-label" class="VPDocAsideOutline" data-v-3f215769 data-v-60d5052e><div class="content" data-v-60d5052e><div class="outline-marker" data-v-60d5052e></div><div aria-level="2" class="outline-title" id="doc-outline-aria-label" role="heading" data-v-60d5052e>本页目录</div><ul class="VPDocOutlineItem root" data-v-60d5052e data-v-1ce71065><!--[--><!--]--></ul></div></nav><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-7011f0d8><div class="content-container" data-v-7011f0d8><!--[--><!--]--><main class="main" data-v-7011f0d8><div style="position:relative;" class="vp-doc _qq-music-api_guide_architecture" data-v-7011f0d8><div><h1 id="代码架构说明" tabindex="-1">代码架构说明 <a class="header-anchor" href="#代码架构说明" aria-label="Permalink to “代码架构说明”">​</a></h1><p>本文档介绍项目的代码架构和抽象设计。</p><h2 id="代码抽象" tabindex="-1">代码抽象 <a class="header-anchor" href="#代码抽象" aria-label="Permalink to “代码抽象”">​</a></h2><p>为了提高代码的可维护性和开发效率,项目进行了以下代码抽象:</p><h3 id="_1-统一的-api-类型定义" tabindex="-1">1. 统一的 API 类型定义 <a class="header-anchor" href="#_1-统一的-api-类型定义" aria-label="Permalink to “1. 统一的 API 类型定义”">​</a></h3><p><strong>文件位置</strong>: <a href="../../types/api.ts"><code>types/api.ts</code></a></p><p>定义了项目中所有 API 函数使用的通用类型:</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// API 响应结构</span></span>
24
24
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
25
25
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> status</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">number</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
26
26
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> body</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: {</span></span>
@@ -46,15 +46,15 @@
46
46
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// API 函数类型定义</span></span>
47
47
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> type</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiFunction</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">&lt;</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">T</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> extends</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">&gt;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> (</span></span>
48
48
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> options</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">T</span></span>
49
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =&gt;</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> Promise</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">&lt;</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">ApiResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">&gt;;</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 单一事实来源,避免重复定义</li><li>✅ 类型安全,减少类型错误</li><li>✅ 易于维护和修改</li></ul><h3 id="_2-api-响应工具函数" tabindex="-1">2. API 响应工具函数 <a class="header-anchor" href="#_2-api-响应工具函数" aria-label="Permalink to &quot;2. API 响应工具函数&quot;">​</a></h3><p><strong>文件位置</strong>: <a href="../../util/apiResponse.ts"><code>util/apiResponse.ts</code></a></p><p>提供了统一的 API 响应处理工具:</p><h4 id="successresponse-data-status" tabindex="-1"><code>successResponse(data, status?)</code> <a class="header-anchor" href="#successresponse-data-status" aria-label="Permalink to &quot;`successResponse(data, status?)`&quot;">​</a></h4><p>创建成功的 API 响应</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> successResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
49
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =&gt;</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> Promise</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">&lt;</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">ApiResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">&gt;;</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 单一事实来源,避免重复定义</li><li>✅ 类型安全,减少类型错误</li><li>✅ 易于维护和修改</li></ul><h3 id="_2-api-响应工具函数" tabindex="-1">2. API 响应工具函数 <a class="header-anchor" href="#_2-api-响应工具函数" aria-label="Permalink to 2. API 响应工具函数”">​</a></h3><p><strong>文件位置</strong>: <a href="../../util/apiResponse.ts"><code>util/apiResponse.ts</code></a></p><p>提供了统一的 API 响应处理工具:</p><h4 id="successresponse-data-status" tabindex="-1"><code>successResponse(data, status?)</code> <a class="header-anchor" href="#successresponse-data-status" aria-label="Permalink to successResponse(data, status?)">​</a></h4><p>创建成功的 API 响应</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> successResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
50
50
  <span class="line"></span>
51
51
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 使用示例</span></span>
52
52
  <span class="line"><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;">const </span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">response</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> successResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">({ </span><span style="--shiki-light:#998418;--shiki-dark:#B8A965;">id</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2F798A;--shiki-dark:#4C9A91;">1</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">, </span><span style="--shiki-light:#998418;--shiki-dark:#B8A965;">name</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">test</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> });</span></span>
53
- <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 返回:{ status: 200, body: { response: { id: 1, name: &#39;test&#39; } } }</span></span></code></pre></div><h4 id="errorresponse-error-status" tabindex="-1"><code>errorResponse(error, status?)</code> <a class="header-anchor" href="#errorresponse-error-status" aria-label="Permalink to &quot;`errorResponse(error, status?)`&quot;">​</a></h4><p>创建错误的 API 响应</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> errorResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
53
+ <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 返回:{ status: 200, body: { response: { id: 1, name: &#39;test&#39; } } }</span></span></code></pre></div><h4 id="errorresponse-error-status" tabindex="-1"><code>errorResponse(error, status?)</code> <a class="header-anchor" href="#errorresponse-error-status" aria-label="Permalink to errorResponse(error, status?)">​</a></h4><p>创建错误的 API 响应</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> errorResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
54
54
  <span class="line"></span>
55
55
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 使用示例</span></span>
56
56
  <span class="line"><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;">const </span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">response</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> errorResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">Not found</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#2F798A;--shiki-dark:#4C9A91;"> 404</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span>
57
- <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 返回:{ status: 404, body: { error: &#39;Not found&#39; } }</span></span></code></pre></div><h4 id="handleapi-promise-options" tabindex="-1"><code>handleApi(promise, options?)</code> <a class="header-anchor" href="#handleapi-promise-options" aria-label="Permalink to &quot;`handleApi(promise, options?)`&quot;">​</a></h4><p>处理 API Promise,自动包装成功和错误响应</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
57
+ <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 返回:{ status: 404, body: { error: &#39;Not found&#39; } }</span></span></code></pre></div><h4 id="handleapi-promise-options" tabindex="-1"><code>handleApi(promise, options?)</code> <a class="header-anchor" href="#handleapi-promise-options" aria-label="Permalink to handleApi(promise, options?)">​</a></h4><p>处理 API Promise,自动包装成功和错误响应</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
58
58
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
59
59
  <span class="line"></span>
60
60
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 基本使用</span></span>
@@ -79,7 +79,7 @@
79
79
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
80
80
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
81
81
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> );</span></span>
82
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 消除重复的 try-catch 代码</li><li>✅ 统一的错误处理</li><li>✅ 代码更简洁,每个 API 文件减少约 15-20 行代码</li></ul><h3 id="_3-controller-工厂函数" tabindex="-1">3. Controller 工厂函数 <a class="header-anchor" href="#_3-controller-工厂函数" aria-label="Permalink to &quot;3. Controller 工厂函数&quot;">​</a></h3><p><strong>文件位置</strong>: <a href="../../routers/util.ts"><code>routers/util.ts</code></a></p><p>提供了创建 Controller 的工厂函数:</p><h4 id="createcontroller-apifunction-options" tabindex="-1"><code>createController(apiFunction, options?)</code> <a class="header-anchor" href="#createcontroller-apifunction-options" aria-label="Permalink to &quot;`createController(apiFunction, options?)`&quot;">​</a></h4><p>创建 GET 请求的 Controller</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
82
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 消除重复的 try-catch 代码</li><li>✅ 统一的错误处理</li><li>✅ 代码更简洁,每个 API 文件减少约 15-20 行代码</li></ul><h3 id="_3-controller-工厂函数" tabindex="-1">3. Controller 工厂函数 <a class="header-anchor" href="#_3-controller-工厂函数" aria-label="Permalink to 3. Controller 工厂函数”">​</a></h3><p><strong>文件位置</strong>: <a href="../../routers/util.ts"><code>routers/util.ts</code></a></p><p>提供了创建 Controller 的工厂函数:</p><h4 id="createcontroller-apifunction-options" tabindex="-1"><code>createController(apiFunction, options?)</code> <a class="header-anchor" href="#createcontroller-apifunction-options" aria-label="Permalink to createController(apiFunction, options?)">​</a></h4><p>创建 GET 请求的 Controller</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
83
83
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> getSingerDesc</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../module</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
84
84
  <span class="line"></span>
85
85
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 基本使用</span></span>
@@ -92,17 +92,17 @@
92
92
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> validator</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">([</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">singermid</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">]),</span></span>
93
93
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> errorMessage</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">缺少 singermid 参数</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span></span>
94
94
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
95
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><h4 id="createpostcontroller-apifunction-options" tabindex="-1"><code>createPostController(apiFunction, options?)</code> <a class="header-anchor" href="#createpostcontroller-apifunction-options" aria-label="Permalink to &quot;`createPostController(apiFunction, options?)`&quot;">​</a></h4><p>创建 POST 请求的 Controller</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createPostController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
95
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><h4 id="createpostcontroller-apifunction-options" tabindex="-1"><code>createPostController(apiFunction, options?)</code> <a class="header-anchor" href="#createpostcontroller-apifunction-options" aria-label="Permalink to createPostController(apiFunction, options?)">​</a></h4><p>创建 POST 请求的 Controller</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createPostController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
96
96
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> batchGetSongLists</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../module</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
97
97
  <span class="line"></span>
98
- <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> default</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> createPostController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">batchGetSongLists</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><h4 id="validaterequired-fields" tabindex="-1"><code>validateRequired(fields)</code> <a class="header-anchor" href="#validaterequired-fields" aria-label="Permalink to &quot;`validateRequired(fields)`&quot;">​</a></h4><p>参数验证工具</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
98
+ <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> default</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> createPostController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">batchGetSongLists</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><h4 id="validaterequired-fields" tabindex="-1"><code>validateRequired(fields)</code> <a class="header-anchor" href="#validaterequired-fields" aria-label="Permalink to validateRequired(fields)">​</a></h4><p>参数验证工具</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
99
99
  <span class="line"></span>
100
100
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> default</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span></span>
101
101
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> someApiFunction</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span></span>
102
102
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
103
103
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> validator</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">([</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">singermid</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">, </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">songmid</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">])</span></span>
104
104
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
105
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 减少 Controller 代码重复</li><li>✅ 统一的错误处理</li><li>✅ 参数验证标准化</li></ul><h3 id="_4-统一的全局类型" tabindex="-1">4. 统一的全局类型 <a class="header-anchor" href="#_4-统一的全局类型" aria-label="Permalink to &quot;4. 统一的全局类型&quot;">​</a></h3><p><strong>文件位置</strong>: <a href="../../types/global.d.ts"><code>types/global.d.ts</code></a></p><p>定义了全局 <code>userInfo</code> 对象的类型:</p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> UserInfo</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
105
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 减少 Controller 代码重复</li><li>✅ 统一的错误处理</li><li>✅ 参数验证标准化</li></ul><h3 id="_4-统一的全局类型" tabindex="-1">4. 统一的全局类型 <a class="header-anchor" href="#_4-统一的全局类型" aria-label="Permalink to 4. 统一的全局类型”">​</a></h3><p><strong>文件位置</strong>: <a href="../../types/global.d.ts"><code>types/global.d.ts</code></a></p><p>定义了全局 <code>userInfo</code> 对象的类型:</p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> UserInfo</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
106
106
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> loginUin</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">string</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
107
107
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> uin</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;">?</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">string</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
108
108
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> cookie</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">string</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
@@ -114,7 +114,7 @@
114
114
  <span class="line"></span>
115
115
  <span class="line"><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;">declare</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> global</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
116
116
  <span class="line"><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> var </span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">userInfo</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">UserInfo</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
117
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">}</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 类型定义集中管理</li><li>✅ 避免类型冲突</li><li>✅ 全局类型安全</li></ul><h2 id="重构前后对比" tabindex="-1">重构前后对比 <a class="header-anchor" href="#重构前后对比" aria-label="Permalink to &quot;重构前后对比&quot;">​</a></h2><h3 id="重构前-旧代码" tabindex="-1">重构前(旧代码) <a class="header-anchor" href="#重构前-旧代码" aria-label="Permalink to &quot;重构前(旧代码)&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
117
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">}</span></span></code></pre></div><p><strong>优势</strong>:</p><ul><li>✅ 类型定义集中管理</li><li>✅ 避免类型冲突</li><li>✅ 全局类型安全</li></ul><h2 id="重构前后对比" tabindex="-1">重构前后对比 <a class="header-anchor" href="#重构前后对比" aria-label="Permalink to “重构前后对比”">​</a></h2><h3 id="重构前-旧代码" tabindex="-1">重构前(旧代码) <a class="header-anchor" href="#重构前-旧代码" aria-label="Permalink to “重构前(旧代码)”">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
118
118
  <span class="line"></span>
119
119
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
120
120
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> method</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;">?</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">string</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
@@ -163,7 +163,7 @@
163
163
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
164
164
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> };</span></span>
165
165
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> });</span></span>
166
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><p><strong>代码行数</strong>: 约 35 行</p><h3 id="重构后-新代码" tabindex="-1">重构后(新代码) <a class="header-anchor" href="#重构后-新代码" aria-label="Permalink to &quot;重构后(新代码)&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
166
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><p><strong>代码行数</strong>: 约 35 行</p><h3 id="重构后-新代码" tabindex="-1">重构后(新代码) <a class="header-anchor" href="#重构后-新代码" aria-label="Permalink to “重构后(新代码)”">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
167
167
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
168
168
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> type</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../types/api</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
169
169
  <span class="line"></span>
@@ -184,7 +184,7 @@
184
184
  <span class="line"><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> options</span></span>
185
185
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> })</span></span>
186
186
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> );</span></span>
187
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><p><strong>代码行数</strong>: 约 18 行</p><p><strong>改进</strong>:</p><ul><li>✅ 减少 17 行代码(减少约 48%)</li><li>✅ 移除重复的类型定义</li><li>✅ 移除重复的 try-catch 逻辑</li><li>✅ 使用 async/await 语法更清晰</li></ul><h2 id="controller-重构示例" tabindex="-1">Controller 重构示例 <a class="header-anchor" href="#controller-重构示例" aria-label="Permalink to &quot;Controller 重构示例&quot;">​</a></h2><h3 id="重构前" tabindex="-1">重构前 <a class="header-anchor" href="#重构前" aria-label="Permalink to &quot;重构前&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> Context</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> Next</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">koa</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
187
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><p><strong>代码行数</strong>: 约 18 行</p><p><strong>改进</strong>:</p><ul><li>✅ 减少 17 行代码(减少约 48%)</li><li>✅ 移除重复的类型定义</li><li>✅ 移除重复的 try-catch 逻辑</li><li>✅ 使用 async/await 语法更清晰</li></ul><h2 id="controller-重构示例" tabindex="-1">Controller 重构示例 <a class="header-anchor" href="#controller-重构示例" aria-label="Permalink to Controller 重构示例”">​</a></h2><h3 id="重构前" tabindex="-1">重构前 <a class="header-anchor" href="#重构前" aria-label="Permalink to “重构前”">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> Context</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> Next</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">koa</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
188
188
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> getSingerDesc</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../module</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
189
189
  <span class="line"></span>
190
190
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> default</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> async</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> (</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">ctx</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">Context</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> next</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">Next</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =&gt;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
@@ -206,7 +206,7 @@
206
206
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> response</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">no singermid</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span></span>
207
207
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> };</span></span>
208
208
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
209
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><h3 id="重构后" tabindex="-1">重构后 <a class="header-anchor" href="#重构后" aria-label="Permalink to &quot;重构后&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
209
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><h3 id="重构后" tabindex="-1">重构后 <a class="header-anchor" href="#重构后" aria-label="Permalink to “重构后”">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
210
210
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> getSingerDesc</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../module</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
211
211
  <span class="line"></span>
212
212
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> default</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span></span>
@@ -215,7 +215,7 @@
215
215
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> validator</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">([</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">singermid</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">]),</span></span>
216
216
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> errorMessage</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">no singermid</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span></span>
217
217
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
218
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><p><strong>改进</strong>:</p><ul><li>✅ 从 25 行减少到 8 行</li><li>✅ 参数验证逻辑抽象</li><li>✅ 错误处理统一</li></ul><h2 id="已重构的文件" tabindex="-1">已重构的文件 <a class="header-anchor" href="#已重构的文件" aria-label="Permalink to &quot;已重构的文件&quot;">​</a></h2><h3 id="module-apis-目录-16-个文件" tabindex="-1">Module/APIs 目录(16 个文件) <a class="header-anchor" href="#module-apis-目录-16-个文件" aria-label="Permalink to &quot;Module/APIs 目录(16 个文件)&quot;">​</a></h3><ul><li><code>module/apis/singers/getSimilarSinger.ts</code></li><li><code>module/apis/singers/getSingerDesc.ts</code></li><li><code>module/apis/singers/getSingerMv.ts</code></li><li><code>module/apis/singers/getSingerStarNum.ts</code></li><li><code>module/apis/radio/getRadioLists.ts</code></li><li><code>module/apis/rank/getTopLists.ts</code></li><li><code>module/apis/music/getLyric.ts</code></li><li><code>module/apis/mv/getMvByTag.ts</code></li><li><code>module/apis/digitalAlbum/getDigitalAlbumLists.ts</code></li><li><code>module/apis/search/getHotKey.ts</code></li><li><code>module/apis/search/getSearchByKey.ts</code></li><li><code>module/apis/songLists/songLists.ts</code></li><li><code>module/apis/songLists/songListCategories.ts</code></li><li><code>module/apis/songLists/songListDetail.ts</code></li><li><code>module/apis/album/getAlbumInfo.ts</code></li><li><code>module/apis/comments/getComments.ts</code></li></ul><h3 id="routers-context-目录-部分文件" tabindex="-1">Routers/Context 目录(部分文件) <a class="header-anchor" href="#routers-context-目录-部分文件" aria-label="Permalink to &quot;Routers/Context 目录(部分文件)&quot;">​</a></h3><ul><li><code>routers/context/getDownloadQQMusic.ts</code></li><li><code>routers/context/getSmartbox.ts</code></li><li><code>routers/context/cookies.ts</code></li></ul><h3 id="其他文件" tabindex="-1">其他文件 <a class="header-anchor" href="#其他文件" aria-label="Permalink to &quot;其他文件&quot;">​</a></h3><ul><li><code>routers/types.ts</code> - 移除重复类型定义</li><li><code>config/user-info.ts</code> - 统一类型定义</li><li><code>app.ts</code> - 类型修复</li><li><code>module/config.ts</code> - 类型修复</li></ul><h2 id="统计" tabindex="-1">统计 <a class="header-anchor" href="#统计" aria-label="Permalink to &quot;统计&quot;">​</a></h2><ul><li><strong>代码量减少</strong>: 约 30-40% 的重复代码被移除</li><li><strong>类型安全</strong>: 统一的类型定义减少类型错误</li><li><strong>可维护性</strong>: 类型定义集中,易于修改</li><li><strong>开发效率</strong>: 新增 API 时代码更简洁</li></ul><h2 id="最佳实践" tabindex="-1">最佳实践 <a class="header-anchor" href="#最佳实践" aria-label="Permalink to &quot;最佳实践&quot;">​</a></h2><h3 id="_1-创建新的-api-函数" tabindex="-1">1. 创建新的 API 函数 <a class="header-anchor" href="#_1-创建新的-api-函数" aria-label="Permalink to &quot;1. 创建新的 API 函数&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
218
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><p><strong>改进</strong>:</p><ul><li>✅ 从 25 行减少到 8 行</li><li>✅ 参数验证逻辑抽象</li><li>✅ 错误处理统一</li></ul><h2 id="已重构的文件" tabindex="-1">已重构的文件 <a class="header-anchor" href="#已重构的文件" aria-label="Permalink to “已重构的文件”">​</a></h2><h3 id="module-apis-目录-16-个文件" tabindex="-1">Module/APIs 目录(16 个文件) <a class="header-anchor" href="#module-apis-目录-16-个文件" aria-label="Permalink to Module/APIs 目录(16 个文件)”">​</a></h3><ul><li><code>module/apis/singers/getSimilarSinger.ts</code></li><li><code>module/apis/singers/getSingerDesc.ts</code></li><li><code>module/apis/singers/getSingerMv.ts</code></li><li><code>module/apis/singers/getSingerStarNum.ts</code></li><li><code>module/apis/radio/getRadioLists.ts</code></li><li><code>module/apis/rank/getTopLists.ts</code></li><li><code>module/apis/music/getLyric.ts</code></li><li><code>module/apis/mv/getMvByTag.ts</code></li><li><code>module/apis/digitalAlbum/getDigitalAlbumLists.ts</code></li><li><code>module/apis/search/getHotKey.ts</code></li><li><code>module/apis/search/getSearchByKey.ts</code></li><li><code>module/apis/songLists/songLists.ts</code></li><li><code>module/apis/songLists/songListCategories.ts</code></li><li><code>module/apis/songLists/songListDetail.ts</code></li><li><code>module/apis/album/getAlbumInfo.ts</code></li><li><code>module/apis/comments/getComments.ts</code></li></ul><h3 id="routers-context-目录-部分文件" tabindex="-1">Routers/Context 目录(部分文件) <a class="header-anchor" href="#routers-context-目录-部分文件" aria-label="Permalink to Routers/Context 目录(部分文件)”">​</a></h3><ul><li><code>routers/context/getDownloadQQMusic.ts</code></li><li><code>routers/context/getSmartbox.ts</code></li><li><code>routers/context/cookies.ts</code></li></ul><h3 id="其他文件" tabindex="-1">其他文件 <a class="header-anchor" href="#其他文件" aria-label="Permalink to “其他文件”">​</a></h3><ul><li><code>routers/types.ts</code> - 移除重复类型定义</li><li><code>config/user-info.ts</code> - 统一类型定义</li><li><code>app.ts</code> - 类型修复</li><li><code>module/config.ts</code> - 类型修复</li></ul><h2 id="统计" tabindex="-1">统计 <a class="header-anchor" href="#统计" aria-label="Permalink to “统计”">​</a></h2><ul><li><strong>代码量减少</strong>: 约 30-40% 的重复代码被移除</li><li><strong>类型安全</strong>: 统一的类型定义减少类型错误</li><li><strong>可维护性</strong>: 类型定义集中,易于修改</li><li><strong>开发效率</strong>: 新增 API 时代码更简洁</li></ul><h2 id="最佳实践" tabindex="-1">最佳实践 <a class="header-anchor" href="#最佳实践" aria-label="Permalink to “最佳实践”">​</a></h2><h3 id="_1-创建新的-api-函数" tabindex="-1">1. 创建新的 API 函数 <a class="header-anchor" href="#_1-创建新的-api-函数" aria-label="Permalink to 1. 创建新的 API 函数”">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> request</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/request</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
219
219
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
220
220
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> type</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../types/api</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
221
221
  <span class="line"></span>
@@ -243,7 +243,7 @@
243
243
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
244
244
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
245
245
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> );</span></span>
246
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><h3 id="_2-创建新的-controller" tabindex="-1">2. 创建新的 Controller <a class="header-anchor" href="#_2-创建新的-controller" aria-label="Permalink to &quot;2. 创建新的 Controller&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
246
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><h3 id="_2-创建新的-controller" tabindex="-1">2. 创建新的 Controller <a class="header-anchor" href="#_2-创建新的-controller" aria-label="Permalink to 2. 创建新的 Controller">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> createController</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">./util</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
247
247
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> someApiFunction</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../module</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
248
248
  <span class="line"></span>
249
249
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 简单情况</span></span>
@@ -256,7 +256,7 @@
256
256
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> validator</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">validateRequired</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">([</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">requiredParam1</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">, </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">requiredParam2</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">]),</span></span>
257
257
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> errorMessage</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">缺少必需参数</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span></span>
258
258
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
259
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><h3 id="_3-处理特殊响应" tabindex="-1">3. 处理特殊响应 <a class="header-anchor" href="#_3-处理特殊响应" aria-label="Permalink to &quot;3. 处理特殊响应&quot;">​</a></h3><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> customResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
259
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span></code></pre></div><h3 id="_3-处理特殊响应" tabindex="-1">3. 处理特殊响应 <a class="header-anchor" href="#_3-处理特殊响应" aria-label="Permalink to 3. 处理特殊响应”">​</a></h3><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">,</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> customResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
260
260
  <span class="line"></span>
261
261
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> default</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> async</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> (</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;">options</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;">ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">)</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> =&gt;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
262
262
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> try</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span></span>
@@ -269,16 +269,16 @@
269
269
  <span class="line"><span style="--shiki-light:#998418;--shiki-dark:#B8A965;"> code</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">: </span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">CUSTOM_ERROR</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span></span>
270
270
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> },</span><span style="--shiki-light:#2F798A;--shiki-dark:#4C9A91;"> 500</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">);</span></span>
271
271
  <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
272
- <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><h2 id="迁移指南" tabindex="-1">迁移指南 <a class="header-anchor" href="#迁移指南" aria-label="Permalink to &quot;迁移指南&quot;">​</a></h2><p>如果你需要将旧的 API 文件迁移到新的架构:</p><ol><li><p><strong>移除重复的类型定义</strong></p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 删除这些定义</span></span>
272
+ <span class="line"><span style="--shiki-light:#999999;--shiki-dark:#666666;">};</span></span></code></pre></div><h2 id="迁移指南" tabindex="-1">迁移指南 <a class="header-anchor" href="#迁移指南" aria-label="Permalink to “迁移指南”">​</a></h2><p>如果你需要将旧的 API 文件迁移到新的架构:</p><ol><li><p><strong>移除重复的类型定义</strong></p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 删除这些定义</span></span>
273
273
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> ...</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span>
274
- <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> ...</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span></code></pre></div></li><li><p><strong>导入统一的类型和工具</strong></p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
275
- <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> type</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../types/api</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span></code></pre></div></li><li><p><strong>重构为 async/await 语法</strong></p><div class="language-typescript vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 旧代码</span></span>
274
+ <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">export</span><span style="--shiki-light:#AB5959;--shiki-dark:#CB7676;"> interface</span><span style="--shiki-light:#2E8F82;--shiki-dark:#5DA994;"> ApiResponse</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> ...</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span></span></code></pre></div></li><li><p><strong>导入统一的类型和工具</strong></p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../util/apiResponse</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span>
275
+ <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">import</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> type</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> {</span><span style="--shiki-light:#B07D48;--shiki-dark:#BD976A;"> ApiOptions</span><span style="--shiki-light:#999999;--shiki-dark:#666666;"> }</span><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;"> from</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;"> &#39;</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;">../../../types/api</span><span style="--shiki-light:#B5695977;--shiki-dark:#C98A7D77;">&#39;</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">;</span></span></code></pre></div></li><li><p><strong>重构为 async/await 语法</strong></p><div class="language-typescript"><button title="Copy Code" class="copy"></button><span class="lang">typescript</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 旧代码</span></span>
276
276
  <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">return</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> request</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(...).</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">then</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(...).</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">catch</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(...);</span></span>
277
277
  <span class="line"></span>
278
278
  <span class="line"><span style="--shiki-light:#A0ADA0;--shiki-dark:#758575DD;">// 新代码</span></span>
279
- <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">return</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">request</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(...));</span></span></code></pre></div></li><li><p><strong>测试验证</strong></p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes vitesse-light vitesse-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">npx</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;"> tsc</span><span style="--shiki-light:#A65E2B;--shiki-dark:#C99076;"> --noEmit</span></span>
280
- <span class="line"><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">npm</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;"> run</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;"> dev</span></span></code></pre></div></li></ol><h2 id="总结" tabindex="-1">总结 <a class="header-anchor" href="#总结" aria-label="Permalink to &quot;总结&quot;">​</a></h2><p>通过代码抽象,我们实现了:</p><ul><li>✅ <strong>统一的类型系统</strong> - 所有 API 使用相同的类型定义</li><li>✅ <strong>一致的错误处理</strong> - 统一的 try-catch 模式</li><li>✅ <strong>简洁的代码结构</strong> - 减少 30-40% 的重复代码</li><li>✅ <strong>更好的可维护性</strong> - 类型定义集中管理</li><li>✅ <strong>更高的开发效率</strong> - 新增 API 时代码更简洁</li></ul><p>这些改进使得项目更易于维护和扩展,同时也提高了开发效率。</p></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><div class="edit-link" data-v-e257564d><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://github.com/sansenjian/qq-music-api/edit/main/docs/guide/architecture.md" target="_blank" rel="noreferrer" data-v-e257564d><!--[--><span class="vpi-square-pen edit-link-icon" data-v-e257564d></span> 在 GitHub 上编辑此页面<!--]--></a></div><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-e98dd255>Last updated: <time datetime="2026-03-14T14:49:32.000Z" data-v-e98dd255></time></p></div></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-e257564d><span class="visually-hidden" id="doc-footer-aria-label" data-v-e257564d>Pager</span><div class="pager" data-v-e257564d><a class="VPLink link pager-link prev" href="/qq-music-api/reference/response-format.html" data-v-e257564d><!--[--><span class="desc" data-v-e257564d>Previous page</span><span class="title" data-v-e257564d>响应格式</span><!--]--></a></div><div class="pager" data-v-e257564d><!----></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-5d98c3a5 data-v-e315a0ad><div class="container" data-v-e315a0ad><p class="message" data-v-e315a0ad>基于 MIT 许可发布</p><p class="copyright" data-v-e315a0ad>Copyright © 2020-present Sansenjian</p></div></footer><!--[--><!--]--></div></div>
281
- <script>window.__VP_HASH_MAP__=JSON.parse("{\"api_comments.md\":\"79Q_C8Qp\",\"api_index.md\":\"CU3By8tw\",\"api_music.md\":\"B1AzLePX\",\"api_other.md\":\"DCg4bzA7\",\"api_playlist.md\":\"8ACJ3QqD\",\"api_rank.md\":\"B8IP2ZRy\",\"api_search.md\":\"DO9J6nvp\",\"api_singer.md\":\"CcL32xuN\",\"api_user.md\":\"Cb7Ky3Sn\",\"changelog-architecture.md\":\"r40JGJZK\",\"cookie_config_guide.md\":\"BVXl7WHu\",\"fallback_mode_guide.md\":\"BBdcIdh_\",\"guide_architecture.md\":\"CzgqynmB\",\"guide_authentication.md\":\"a8yTA8Xe\",\"guide_index.md\":\"BgUUL6fI\",\"guide_installation.md\":\"BCZ4jBl_\",\"guide_quickstart.md\":\"9-4dA6wS\",\"index.md\":\"z0hAJioN\",\"readme.md\":\"D6Tw0nRd\",\"reference_response-format.md\":\"VvQTLDZr\",\"test_user_playlists.md\":\"DSt20Igj\",\"user_avatar_guide.md\":\"CVHPs2Dn\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"QQ Music API\",\"description\":\"QQ 音乐 API 接口文档\",\"base\":\"/qq-music-api/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"logo\":\"/logo.svg\",\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"使用指南\",\"link\":\"/guide/\"},{\"text\":\"API 文档\",\"link\":\"/api/\"},{\"text\":\"用户能力\",\"link\":\"/api/user\"},{\"text\":\"架构说明\",\"link\":\"/guide/architecture\"}],\"sidebar\":[{\"text\":\"开始使用\",\"items\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"使用指南\",\"link\":\"/guide/\"},{\"text\":\"安装指南\",\"link\":\"/guide/installation\"},{\"text\":\"快速开始\",\"link\":\"/guide/quickstart\"}]},{\"text\":\"认证与用户\",\"items\":[{\"text\":\"认证与登录\",\"link\":\"/guide/authentication\"},{\"text\":\"用户接口\",\"link\":\"/api/user\"}]},{\"text\":\"API 文档\",\"items\":[{\"text\":\"API 总览\",\"link\":\"/api/\"},{\"text\":\"音乐相关\",\"link\":\"/api/music\"},{\"text\":\"歌手相关\",\"link\":\"/api/singer\"},{\"text\":\"歌单相关\",\"link\":\"/api/playlist\"},{\"text\":\"排行榜\",\"link\":\"/api/rank\"},{\"text\":\"搜索\",\"link\":\"/api/search\"},{\"text\":\"评论\",\"link\":\"/api/comments\"},{\"text\":\"其他接口\",\"link\":\"/api/other\"}]},{\"text\":\"开发与维护\",\"items\":[{\"text\":\"响应格式\",\"link\":\"/reference/response-format\"},{\"text\":\"代码架构\",\"link\":\"/guide/architecture\"}]}],\"aside\":true,\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/sansenjian/qq-music-api\"}],\"footer\":{\"message\":\"基于 MIT 许可发布\",\"copyright\":\"Copyright © 2020-present Sansenjian\"},\"editLink\":{\"pattern\":\"https://github.com/sansenjian/qq-music-api/edit/main/docs/:path\",\"text\":\"在 GitHub 上编辑此页面\"},\"search\":{\"provider\":\"local\",\"options\":{\"locales\":{\"root\":{\"translations\":{\"button\":{\"buttonText\":\"搜索\",\"buttonAriaLabel\":\"搜索文档\"},\"modal\":{\"noResultsText\":\"无法找到相关结果\",\"resetButtonTitle\":\"清除查询条件\",\"footer\":{\"selectText\":\"选择\",\"navigateText\":\"切换\"}}}}}}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
279
+ <span class="line"><span style="--shiki-light:#1E754F;--shiki-dark:#4D9375;">return</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;"> handleApi</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(</span><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">request</span><span style="--shiki-light:#999999;--shiki-dark:#666666;">(...));</span></span></code></pre></div></li><li><p><strong>测试验证</strong></p><div class="language-bash"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes vitesse-light vitesse-dark" style="--shiki-light:#393a34;--shiki-dark:#dbd7caee;--shiki-light-bg:#ffffff;--shiki-dark-bg:#121212;" tabindex="0" dir="ltr"><code><span class="line"><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">npx</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;"> tsc</span><span style="--shiki-light:#A65E2B;--shiki-dark:#C99076;"> --noEmit</span></span>
280
+ <span class="line"><span style="--shiki-light:#59873A;--shiki-dark:#80A665;">npm</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;"> run</span><span style="--shiki-light:#B56959;--shiki-dark:#C98A7D;"> dev</span></span></code></pre></div></li></ol><h2 id="总结" tabindex="-1">总结 <a class="header-anchor" href="#总结" aria-label="Permalink to “总结”">​</a></h2><p>通过代码抽象,我们实现了:</p><ul><li>✅ <strong>统一的类型系统</strong> - 所有 API 使用相同的类型定义</li><li>✅ <strong>一致的错误处理</strong> - 统一的 try-catch 模式</li><li>✅ <strong>简洁的代码结构</strong> - 减少 30-40% 的重复代码</li><li>✅ <strong>更好的可维护性</strong> - 类型定义集中管理</li><li>✅ <strong>更高的开发效率</strong> - 新增 API 时代码更简洁</li></ul><p>这些改进使得项目更易于维护和扩展,同时也提高了开发效率。</p></div></div></main><footer class="VPDocFooter" data-v-7011f0d8 data-v-e257564d><!--[--><!--]--><div class="edit-info" data-v-e257564d><div class="edit-link" data-v-e257564d><a class="VPLink link vp-external-link-icon no-icon edit-link-button" href="https://github.com/sansenjian/qq-music-api/edit/main/docs/guide/architecture.md" target="_blank" rel="noreferrer" data-v-e257564d><!--[--><span class="vpi-square-pen edit-link-icon" data-v-e257564d></span> 在 GitHub 上编辑此页面<!--]--></a></div><div class="last-updated" data-v-e257564d><p class="VPLastUpdated" data-v-e257564d data-v-3c637f39>最后更新于: <time datetime="2026-05-17T15:29:28.000Z" data-v-3c637f39></time></p></div></div><nav class="prev-next" aria-labelledby="doc-footer-aria-label" data-v-e257564d><span class="visually-hidden" id="doc-footer-aria-label" data-v-e257564d>Pager</span><div class="pager" data-v-e257564d><a class="VPLink link pager-link prev" href="/qq-music-api/reference/response-format.html" data-v-e257564d><!--[--><span class="desc" data-v-e257564d>上一页</span><span class="title" data-v-e257564d>响应格式</span><!--]--></a></div><div class="pager" data-v-e257564d><!----></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-0cf61682 data-v-c3855bb3><div class="container" data-v-c3855bb3><p class="message" data-v-c3855bb3>基于 MIT 许可发布</p><p class="copyright" data-v-c3855bb3>Copyright © 2020-present Sansenjian</p></div></footer><!--[--><!--]--></div></div>
281
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"api_comments.md\":\"5nDhrWa8\",\"api_index.md\":\"DdG1WHkZ\",\"api_music.md\":\"D66hq-_4\",\"api_other.md\":\"9KhspVEM\",\"api_playground.md\":\"BZBvYMm2\",\"api_playlist.md\":\"BQK32ZyE\",\"api_rank.md\":\"z7YBwVgw\",\"api_search.md\":\"GfzIBRfc\",\"api_singer.md\":\"BDR-_qDH\",\"api_user.md\":\"Dx8BWGrb\",\"changelog-architecture.md\":\"CYHmaBdY\",\"cookie_config_guide.md\":\"Nvywo7CW\",\"degrade_examples.md\":\"Cz2J-qwE\",\"fallback_mode_guide.md\":\"wKA9yqoI\",\"guide_architecture.md\":\"SHnKkzwb\",\"guide_authentication.md\":\"CZCKocgR\",\"guide_index.md\":\"CkJ-jjL0\",\"guide_installation.md\":\"D2TBzILh\",\"guide_quickstart.md\":\"J7Sib8wg\",\"index.md\":\"ClwYf6Qc\",\"quick_start.md\":\"D5KfDgbs\",\"readme.md\":\"CHbArqA7\",\"reference_response-format.md\":\"BrGoGoPV\",\"test_user_playlists.md\":\"BfBxYbaM\",\"user_avatar_guide.md\":\"D5Rti1Gg\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"QQ Music API\",\"description\":\"QQ 音乐 API 接口文档\",\"base\":\"/qq-music-api/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"logo\":\"/logo.svg\",\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"使用指南\",\"link\":\"/guide/\"},{\"text\":\"API 文档\",\"link\":\"/api/\"},{\"text\":\"API 调试台\",\"link\":\"/api/playground\"},{\"text\":\"用户能力\",\"link\":\"/api/user\"},{\"text\":\"架构说明\",\"link\":\"/guide/architecture\"}],\"sidebar\":[{\"text\":\"开始使用\",\"items\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"使用指南\",\"link\":\"/guide/\"},{\"text\":\"安装指南\",\"link\":\"/guide/installation\"},{\"text\":\"快速开始\",\"link\":\"/guide/quickstart\"},{\"text\":\"快速使用指南\",\"link\":\"/QUICK_START\"},{\"text\":\"降级服务示例\",\"link\":\"/DEGRADE_EXAMPLES\"}]},{\"text\":\"认证与用户\",\"items\":[{\"text\":\"认证与登录\",\"link\":\"/guide/authentication\"},{\"text\":\"用户接口\",\"link\":\"/api/user\"}]},{\"text\":\"API 文档\",\"items\":[{\"text\":\"API 总览\",\"link\":\"/api/\"},{\"text\":\"音乐相关\",\"link\":\"/api/music\"},{\"text\":\"歌手相关\",\"link\":\"/api/singer\"},{\"text\":\"歌单相关\",\"link\":\"/api/playlist\"},{\"text\":\"排行榜\",\"link\":\"/api/rank\"},{\"text\":\"搜索\",\"link\":\"/api/search\"},{\"text\":\"评论\",\"link\":\"/api/comments\"},{\"text\":\"其他接口\",\"link\":\"/api/other\"},{\"text\":\"API 调试台\",\"link\":\"/api/playground\"}]},{\"text\":\"开发与维护\",\"items\":[{\"text\":\"响应格式\",\"link\":\"/reference/response-format\"},{\"text\":\"代码架构\",\"link\":\"/guide/architecture\"}]}],\"aside\":true,\"outline\":{\"level\":[2,3],\"label\":\"本页目录\"},\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/sansenjian/qq-music-api\"}],\"footer\":{\"message\":\"基于 MIT 许可发布\",\"copyright\":\"Copyright © 2020-present Sansenjian\"},\"docFooter\":{\"prev\":\"上一页\",\"next\":\"下一页\"},\"lastUpdated\":{\"text\":\"最后更新于\",\"formatOptions\":{\"dateStyle\":\"short\",\"timeStyle\":\"short\",\"forceLocale\":true}},\"editLink\":{\"pattern\":\"https://github.com/sansenjian/qq-music-api/edit/main/docs/:path\",\"text\":\"在 GitHub 上编辑此页面\"},\"darkModeSwitchLabel\":\"主题\",\"lightModeSwitchTitle\":\"切换到浅色模式\",\"darkModeSwitchTitle\":\"切换到深色模式\",\"sidebarMenuLabel\":\"菜单\",\"returnToTopLabel\":\"返回顶部\",\"skipToContentLabel\":\"跳转到内容\",\"notFound\":{\"title\":\"页面未找到\",\"quote\":\"你访问的文档页不存在,可能已被移动或删除。\",\"link\":\"/\",\"linkLabel\":\"返回首页\",\"linkText\":\"返回首页\"},\"search\":{\"provider\":\"local\",\"options\":{\"detailedView\":\"auto\",\"translations\":{\"button\":{\"buttonText\":\"搜索\",\"buttonAriaLabel\":\"搜索文档\"},\"modal\":{\"displayDetails\":\"显示详细列表\",\"backButtonTitle\":\"返回\",\"noResultsText\":\"无法找到相关结果\",\"resetButtonTitle\":\"清除查询条件\",\"footer\":{\"selectText\":\"选择\",\"selectKeyAriaLabel\":\"回车键\",\"navigateText\":\"切换\",\"navigateUpKeyAriaLabel\":\"上箭头\",\"navigateDownKeyAriaLabel\":\"下箭头\",\"closeText\":\"关闭\",\"closeKeyAriaLabel\":\"Esc 键\"}}}}}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false,\"additionalConfig\":{}}");</script>
282
282
 
283
283
  </body>
284
284
  </html>