Files
Situation-Awareness-Platfor…/实习讲解/经历3-API接口前后端集成详解.md
cfy666 c1e9a4be83 chore: sync local changes and add documentation
- Update yarn.lock
- Add project implementation docs in docs/
- Add personal internship experience notes in 实习讲解/
2026-06-29 19:47:30 +08:00

389 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# API 接口前后端集成 — 面试版
> 简历原话:**"协作设计可信态势感知平台API接口完成50+数据接口的前后端集成"**
>
> 这篇文档帮你理解 API 集成层到底做了什么、怎么做的,以及面试时怎么讲。
---
## 一、先搞清楚API 集成层是什么?
API 集成层是前端和后端之间的"翻译官"和"交通管制员"。它不是简单的 `axios.get('/xxx')`,而是一整套基础设施:
```
页面组件Vue 组件)
│ 调用 API 函数
API 函数层29 个文件641 个函数)
→ 定义接口 URL、method、参数格式
│ 调用 request()
请求基础设施request.ts273 行)
→ Axios 实例、请求拦截器、响应拦截器
→ AES 加密/解密、Token 注入、Token 过期自动刷新
→ 错误统一处理、缓存降级
│ HTTP 请求
后端服务器
```
**一句话概括**:我参与设计和集成了平台的 API 通信层,包括定义了 50+ 个态势感知相关的数据接口并搭建了完整的请求基础设施加密、Token 刷新、错误处理、缓存降级),覆盖全平台 641 个接口。
---
## 二、API 整体规模
| 数据 | 数值 |
|------|------|
| API 函数总数 | **641 个** |
| API 文件数 | **29 个** |
| 金银湖态势感知相关 | **106 个**situation.ts 50 + index.ts 45 + home.ts 5 + auth.ts 3 + scanCenter.ts 3 |
| 最大的文件 | `repo/index.ts`161 个函数) |
### 按模块分布
| 模块 | 文件 | 函数数 | 负责什么 |
|------|------|--------|---------|
| **态势感知看板** | `jyh/situation.ts` | 50 | 威胁地图、CVE 趋势、组件排行、漏洞分布等 |
| **金银湖核心** | `jyh/index.ts` | 45 | AI 对话、版本详情、SBOM、许可证、修复建议 |
| **仓库管理** | `repo/index.ts` | 161 | 仓库 CRUD、分支、标签、Wiki、文件、Webhook |
| **组织管理** | `org/index.ts` | 55 | 组织 CRUD、成员、首页、CLA、开发者门户 |
| **用户管理** | `user/index.ts` | 55+ | 登录注册、OAuth、个人资料、SSH 密钥、Token |
| **合并请求** | `merge/index.ts` | 62 | MR 创建/审查、差异对比、代码评审、门禁 |
| **讨论系统** | `discussion/index.ts` | 50 | 讨论 CRUD、分类、评论、投票、排行榜 |
| **其他 20+ 个文件** | issue、commit、branch 等 | ~120 | Issue、提交、分支、标签、发布、通知等 |
---
## 三、请求基础设施(面试核心 — request.ts
`src/utils/request.ts`273 行)是整个平台 API 通信的中枢,每一行都在解决实际问题。
### 3.1 整体架构
```
组件调用 API 函数
proxyService(params) ← 创建一个 Axios 实例
├── 请求拦截器 #1注入 Header
│ ├── DP_TOKEN / DP_REFRESH_TOKENToken 头)
│ ├── Authorization: Bearer xxx权限头
│ ├── page-title / page-repo-id / page-ref页面监控头
│ ├── gitcode-utm-source来源追踪头
│ └── URL 前缀重写setPassportPrefix /uc
├── 请求拦截器 #2缓存降级检查
│ └── degradeInterceptor 决定是否读缓存
├── ===== 发出 HTTP 请求 =====
├── 响应拦截器 #1成功处理
│ ├── code===500 → 检查登录状态
│ └── AES 解密响应数据($Decrypt
├── 响应拦截器 #1失败处理
│ ├── 401 → Token 自动刷新refreshing 锁 + 请求队列)
│ ├── 其他 4xx/5xx → dealWarning防抖 200ms
│ └── 网络超时 → 静默处理
└── 响应拦截器 #2缓存降级存储
└── 成功时存缓存,失败时读缓存返回
```
### 3.2 AES 加密解密
```typescript
// request.ts — 所有响应数据经过 AES-128-CBC 解密
import CryptoJS from 'crypto-js';
const sKey = CryptoJS.enc.Utf8.parse('mXzfCSPBKmEA8aLq');
const iv = CryptoJS.enc.Utf8.parse('tbeJJLC6dZQXXtWr');
// 解密:响应拦截器中自动调用
const $Decrypt = (text) => {
let src = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Base64.parse(text));
let bytes = CryptoJS.AES.decrypt(src, sKey, {
iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7
});
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
};
// 响应拦截器中response.data.data = $Decrypt(response.data.data)
```
**为什么用加密?** 态势感知平台涉及敏感的安全数据AES-128-CBC 加密保证了传输过程中即使被截获也无法直接读取。
### 3.3 Token 自动刷新 + 请求队列
这是整个基础设施中设计最巧妙的部分——**当 Token 过期时,多个并发请求只触发一次刷新**
```typescript
// request.ts — Token 刷新逻辑(简化版)
let refreshing = false; // 刷新锁
const queue = []; // 请求等待队列
// 响应拦截器的错误处理分支
async (error) => {
if (response?.status === 401 && Token && ) {
if (refreshing) {
// 情况 A已经有刷新在进行 → 当前请求排队等待
return new Promise((resolve) => {
queue.unshift({ config, resolve });
});
}
// 情况 B第一个遇到 401 的请求 → 执行刷新
refreshing = true;
const res = await refreshToken(); // 调刷新接口
refreshing = false;
if (res.status === 200) {
// 刷新成功 → 更新 Token → 重放所有排队的请求
localStorage.setItem('op_access_token', newToken);
queue.forEach(({ config, resolve }) => {
config.headers.Authorization = `Bearer ${newToken}`;
resolve(axios(config)); // 用新 Token 重发
});
queue.splice(0); // 清空队列
return axios(config); // 重发当前请求
}
}
}
```
**场景**:用户打开一个有 5 个图表的页面5 个请求同时发出,全部返回 401。第一个请求触发 `refreshToken`,其余 4 个进入队列等待。刷新成功后5 个请求用新 Token 全部重发。**不会出现 5 个请求各自刷新一次 Token 的情况。**
### 3.4 错误统一处理status.ts
```typescript
// status.ts — HTTP 状态码 → 用户提示 + 事件通知
export function showMessage(res) {
switch (res.status) {
case 400: return res.data.error_message; // 参数错误
case 401: emitEvent('logout', ...); break; // 未授权 → 触发登出
case 403: emitEvent('forbiddenRefresh'); // 无权限 → 刷新页面
case 404: break; // 不存在 → 不提示
case 408: return '请求超时';
case 500: return '服务器错误';
case 502: return '网络错误';
case 504: return '网络超时';
default: return res.data.error_message || '连接出错';
}
}
// 用防抖包裹200ms防止短时间内多次弹错误提示
export function dealWarning() {
return debounce((res) => {
const msg = showMessage(res);
if (msg) Message.error(msg);
}, 200);
}
```
**面试话术**
> "请求基础设施有四个关键设计。第一AES-128-CBC 加密传输敏感数据在传输过程中全程加密。第二Token 自动刷新 + 请求队列——用 refreshing 锁和 Promise 队列机制,保证多个并发的 401 请求只触发一次 Token 刷新,其余排队等待,刷新成功后统一重发。第三,错误统一处理——所有 HTTP 错误状态码映射为用户友好的提示信息,并用 200ms 防抖避免短时间弹多次错误。第四API 缓存降级——请求成功时缓存到 IndexedDB失败时自动读缓存兜底。"
---
## 四、API 函数层 — 50+ 态势感知接口怎么组织的?
### 4.1 统一的 API 函数格式
每个 API 函数遵循统一的格式:
```typescript
// src/api/jyh/situation.ts — 示例:态势感知看板 API 函数
import request from '@/utils/request';
// 格式export function 函数名(参数): 返回类型
// ↓ 语义化命名 ↓ TypeScript 泛型
// 全球威胁地图数据
export function mapDataPage1(params?: any): Promise<any> {
return request({
url: `/api/v1/page1/map/mapData`, // ← 接口路径
method: 'get', // ← 请求方法
params // ← GET 方式用 params
});
}
// AI 对话POST 方式)
export function fetchChatUseSql(data): Promise<any> {
return request({
url: '/ai/v1/chat/use_sql', // ← AI 服务接口
method: 'POST', // ← POST 请求
data // ← POST 方式用 data 传 JSON body
});
}
// 文件上传FormData 方式)
export function uploadImage(data): Promise<any> {
const formData = new FormData();
formData.append('file', data.file);
return request({
url: '/api/v1/upload/image',
method: 'POST',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
});
}
```
### 4.2 态势感知相关的 50+ 接口
态势感知模块的接口集中在 `src/api/jyh/situation.ts`50 个函数),按三个页面组织:
| 页面 | 接口前缀 | 端点数 | 干什么 |
|------|---------|--------|--------|
| **第1页全球风险态势** | `/api/v1/page1/*` | 13 个 | 威胁地图、CVE 趋势、组件排行、漏洞分布、行业饼图 |
| **第2页开源生态与贡献** | `/api/v1/page2/*` | ~18 个 | 企业榜单、基础设施覆盖率、高校俱乐部、社区健康、语言竞争力、开发者、热力图 |
| **第3页武汉市开源生态** | `/api/v1/page3/*` | ~19 个 | HarmonyOS 统计、项目分布、开发者、企业、高校、社区、政策、镜像站点 |
加上 `jyh/index.ts` 中的 45 个通用接口AI 对话、版本详情、SBOM、许可证、预警订阅、修复建议、质量任务等金银湖模块共有 **106 个 API**
---
## 五、两个错误处理工具函数
### 5.1 reqCatch — 安全包装 API 调用
```typescript
// src/utils/catch.ts
// 把 try/catch 包装成一个通用函数,避免每个组件都写 try/catch
export async function reqCatch(req, params) {
try {
const data = await req(params);
return { data, error: null }; // 成功 → 返回数据
} catch (e) {
return { data: null, error: e }; // 失败 → 返回错误对象,不会 throw
}
}
// 用法:
const res = await reqCatch(getOrg, { orgId: 'xxx' });
if (!res.error) {
// 成功处理
} else if (res.error.error_code === 404) {
// 404 处理
}
```
### 5.2 reqCatchV2 — 升级版,自动发事件
```typescript
export async function reqCatchV2(req) {
try {
const data = await req();
return { data, error: null };
} catch (e) {
emitEvent('responseError', e); // ← 自动通过事件总线通知全局
return { data: null, error: e };
}
}
```
**为什么有两版?** `reqCatch` 是早期版本,静默捕获错误让调用方自己处理。`reqCatchV2` 增加了自动事件通知——在路由守卫里用 V2错误会被 `eventBus` 监听到,触发统一的 403/404 页面跳转。
---
## 六、API 缓存降级系统degradeInterceptor.ts
这是一个 360 行的自研系统,核心思想是:**API 成功时缓存结果,失败时读缓存兜底**。
```
请求发出
├── 请求拦截器
│ ├── 是否匹配缓存策略URL 正则匹配)
│ ├── 是否处于降级状态?(上次请求失败,且在熔断时间内)
│ │ → 是:直接读 IndexedDB 缓存返回(不发请求)
│ │ → 否:正常发请求(带重试增强)
├── 请求成功 → 响应拦截器
│ └── 缓存结果到 IndexedDB + 更新状态为 success
└── 请求失败 → 响应拦截器
├── 记录失败状态 + 时间戳
└── 读 IndexedDB 缓存返回(用户看到旧数据而不是错误)
```
**关键配置**`storage-apis.ts`
```typescript
const storageApis = [
{ url: '/api/v1/issues', timeout: 5000, retry: 2 },
{ url: '/api/v1/merge_requests', timeout: 5000, retry: 2 },
// ...
];
```
**面试话术**
> "API 缓存降级系统的思路是'请求成功时缓存,失败时读缓存兜底'。在请求拦截器里判断是否命中缓存策略——如果上次请求失败且在熔断时间内,就直接读 IndexedDB 返回缓存数据,不发网络请求。响应成功时自动更新缓存,失败时记录状态并返回历史缓存。还有缓存条数上限控制和过期清理机制。"
---
## 七、面试问答准备
### Q1"完成50+数据接口的前后端集成"具体做了什么?
> 我参与了两方面的工作。第一是接口定义——和 backend 协作设计并集成了 50+ 个态势感知相关的数据接口,按三个页面组织(全球态势、开源生态、武汉生态),定义了接口路径、请求方法、参数格式和返回结构。第二是搭建了完整的请求基础设施——包括 Axios 实例封装、AES-128-CBC 加密传输、Token 自动刷新 + 请求队列、HTTP 状态码统一处理、API 缓存降级系统等。全平台共集成了 641 个 API 函数,分布在 29 个文件中。
### Q2Token 过期自动刷新是怎么实现的?
> 用了一个 `refreshing` 锁 + Promise 请求队列的机制。当请求返回 401 时,先检查 `refreshing` 是否为 true——如果是说明已经有请求在刷新 Token 了,当前请求就包装成一个 Promise 放进等待队列;如果不是,就执行刷新并设 `refreshing = true`。刷新成功后更新 Token然后遍历队列用新 Token 重发所有等待的请求。这样无论同时有多少个请求返回 401都只会发一次刷新请求。
### Q3为什么需要 AES 加密?
> 这个平台涉及安全态势数据,有一定的敏感性。后端返回的数据在传输层用 AES-128-CBC 加密,前端在响应拦截器中自动解密。加密密钥和 IV 是硬编码在前端代码中的生产环境会用更安全的方式管理。加密流程对业务代码完全透明——API 函数只是调用 `request()`,加密解密都在拦截器里自动完成。
### Q4reqCatch 和 reqCatchV2 有什么区别?
> 都是 try/catch 的通用封装,避免每个页面都写 try/catch。区别在于`reqCatch` 静默捕获错误,返回 `{ data, error }` 结构,让调用方自己判断。`reqCatchV2` 在捕获错误后还会通过事件总线 `emitEvent('responseError', e)` 通知全局——这主要用于路由守卫里,发生 403/404 时通过事件触发全局的页面跳转。新代码基本都用 V2。
### Q5API 缓存降级是怎么运作的?
> 这是一套自研的请求降级系统。基于 IndexedDB 做持久化缓存。请求成功时自动缓存响应数据;请求失败时判断是否在熔断时间内——如果是,直接读缓存返回,用户看到的是旧数据而不是错误页面。还有最大缓存条数限制和过期清理机制。通过 `storage-apis.ts` 配置哪些接口走缓存策略,可以设置超时、重试次数、熔断时间等参数。
### Q6HTTP 错误怎么统一处理的?
> 在响应拦截器里统一处理。根据 HTTP 状态码映射不同的行为400 返回参数错误提示、401 触发 Token 刷新或登出、403 触发页面刷新、404 静默不提示、5xx 显示服务端错误提示。错误提示用 `dealWarning` 函数包裹了 200ms 防抖,避免短时间内多个请求同时失败时弹出多条错误消息。还有 `customError: true` 参数,允许特定请求跳过默认错误处理,由调用方自行处理。
---
## 八、关键数字(面试时用)
| 数据 | 数值 |
|------|------|
| 全平台 API 函数总数 | **641 个** |
| API 文件数 | **29 个** |
| 态势感知金银湖API 数 | **106 个** |
| 态势感知看板接口situation.ts | **50 个** |
| 请求基础设施代码量 | `request.ts` 273 行 + `degradeInterceptor.ts` 360 行 + `catch.ts` 46 行 + `status.ts` 76 行 |
| Token 刷新机制 | refreshing 锁 + Promise 队列,确保多并发 401 只刷新一次 |
| 加密方式 | AES-128-CBC密钥 mXzfCSPBKmEA8aLqIV tbeJJLC6dZQXXtWr |
| 请求超时 | 30 秒 |
| 错误提示防抖 | 200ms |
---
## 九、涉及的源码文件(需要看的时候查)
| 做什么 | 文件在哪 |
|--------|----------|
| 请求核心基础设施 | `src/utils/request.ts`273 行Axios、拦截器、加密、Token 刷新) |
| API 缓存降级系统 | `src/utils/degradeInterceptor.ts`360 行IndexedDB 缓存、熔断、重试) |
| 错误捕获包装函数 | `src/utils/catch.ts`reqCatch + reqCatchV2 |
| HTTP 状态码处理 | `src/utils/status.ts`dealWarning + showMessage |
| 缓存配置 | `src/api/storage-apis.ts`(哪些接口走缓存策略) |
| 缓存存储层 | `src/utils/apiStorage.ts`IndexedDB 封装) |
| 态势感知看板 API50 端点) | `src/api/jyh/situation.ts` |
| 金银湖核心 API45 端点) | `src/api/jyh/index.ts` |
| 金银湖首页 API5 端点) | `src/api/jyh/home.ts` |
| 金银湖认证 API3 端点) | `src/api/jyh/auth.ts` |
| 仓库管理 API161 端点) | `src/api/repo/index.ts` |
| 组织管理 API55 端点) | `src/api/org/index.ts` |
| 用户管理 API55+ 端点) | `src/api/user/index.ts` |
| 合并请求 API62 端点) | `src/api/merge/index.ts` |
| 讨论系统 API50 端点) | `src/api/discussion/index.ts` |