chore: sync local changes and add documentation
- Update yarn.lock - Add project implementation docs in docs/ - Add personal internship experience notes in 实习讲解/
This commit is contained in:
244
实习讲解/实习经历整体概览.md
Normal file
244
实习讲解/实习经历整体概览.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# 实习经历 — 整体概览
|
||||
|
||||
> 本文档是对三条实习经历的宏观梳理,后续将针对每条经历分别撰写详细的面试文档。
|
||||
|
||||
---
|
||||
|
||||
## 简历原文
|
||||
|
||||
> **实习经历:可信开源态势感知平台 — 前端开发实习生**
|
||||
>
|
||||
> 1. 参与开发全球风险监测模块,实现威胁情报地图、CVE趋势分析、高危组件排行等10+数据可视化组件
|
||||
> 2. 参与开发TcodeAI助手辅助修复功能,集成金银湖大模型能力,提供智能漏洞修复建议
|
||||
> 3. 协作设计可信态势感知平台API接口,完成50+数据接口的前后端集成
|
||||
|
||||
---
|
||||
|
||||
## 一、三条经历的关系
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 可信开源态势感知平台 │
|
||||
│ │
|
||||
│ ┌──────────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
||||
│ │ 经历1:风险监测模块 │ │经历2:AI修复 │ │经历3:API集成 │ │
|
||||
│ │ 10+可视化组件 │ │金银湖大模型 │ │50+接口前后端 │ │
|
||||
│ │ 威胁地图/趋势/排行 │ │智能修复建议 │ │请求基础设施 │ │
|
||||
│ └────────┬─────────┘ └──────┬───────┘ └───────┬───────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ 前端渲染层 AI 交互层 数据通信层 │
|
||||
│ │
|
||||
│ 三者共同构成平台的核心能力:数据展示 → 智能分析 → 数据获取 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、经历1:全球风险监测模块
|
||||
|
||||
### 做了什么
|
||||
|
||||
参与开发了全球开源风险态势感知监控中心,路由为 `/security`,页面标题为"全球开源风险态势感知监控中心"。实现了 **10+ 个 ECharts 数据可视化组件**,覆盖威胁情报地图、CVE 趋势分析、高危组件排行、漏洞分布、行业分布等多个维度。
|
||||
|
||||
### 涉及的组件
|
||||
|
||||
| 组件 | 图表类型 | 做什么 |
|
||||
|------|---------|--------|
|
||||
| **ThreatIntelMap** | 世界地图 + 散点 + 热力 | 全球威胁情报分布,含国家热力、关键节点、实时警报 |
|
||||
| **ChinaSecurityMap** | 中国地图 + 攻击路径 | 中国安全态势,含省份热力、攻击路径动画 |
|
||||
| **CveTrendChart** | 柱状图 + 折线图 | CVE 月度趋势,支持全球/区域切换 |
|
||||
| **HighRiskComponentRank** | 横向柱状图 | 高危开源组件 Top 10,按 CVSS 评分排序 |
|
||||
| **VulnerabilitySeverityChart** | 堆叠柱状图 | 漏洞严重性分季度分布(高/中/低危) |
|
||||
| **VulnerabilityLanguageChart** | 堆叠面积图 | 12 种编程语言的漏洞趋势(2017-2024) |
|
||||
| **ScatterChart** | 气泡散点图 | 编程语言安全态势,代码活跃度 vs 漏洞密度 |
|
||||
| **IndustryDistribution** | 环形饼图 | 开源风险行业分布(AI、云计算、大数据等 8 大行业) |
|
||||
| **IntelligenceFeed** | 自动滚动列表 | 实时安全情报流,含类型标签和自动滚动 |
|
||||
| **StatsGlass** | 毛玻璃统计卡片 | 4 项全球汇总指标(企业数、高校数、社区活跃度、项目数) |
|
||||
|
||||
### 技术要点
|
||||
|
||||
- 全部基于 **ECharts 6.x** 实现,使用 `echarts.init` + `dispose` 生命周期
|
||||
- 世界地图和中国地图使用 **GeoJSON** 懒加载,几百 KB 的地图数据按需加载
|
||||
- 图表组件通过 **Vite 动态 import** 按需加载,不打包进主 bundle
|
||||
- 使用暗色主题(`#020617` 背景),带浮动粒子动画背景
|
||||
- **13 个后端 API 接口**提供数据(`/api/v1/page1/*`),每个组件有硬编码的兜底数据
|
||||
|
||||
### 后续详细文档
|
||||
|
||||
> → [[经历1-全球风险监测模块详解]] ✅ 已完成
|
||||
|
||||
---
|
||||
|
||||
## 三、经历2:TcodeAI助手辅助修复功能
|
||||
|
||||
### 做了什么
|
||||
|
||||
参与开发了 TcodeAI 助手的辅助修复功能,集成**金银湖大模型**能力,为开源组件的已知漏洞提供 **AI 生成的修复建议**。用户查看某个软件版本时,可以看到该版本依赖库中存在的漏洞,以及对每个漏洞的 AI 修复建议。
|
||||
|
||||
### 功能流程
|
||||
|
||||
```
|
||||
用户进入软件版本详情页
|
||||
│
|
||||
▼
|
||||
切换到 "AI修复建议" Tab
|
||||
│
|
||||
▼
|
||||
POST /api/v1/repo/repair/info ──→ 返回漏洞列表(库名、版本、CVE 等)
|
||||
│
|
||||
▼
|
||||
展示可折叠面板列表(每个受影响的库一个面板)
|
||||
│
|
||||
▼
|
||||
用户点击某个漏洞的 "AI修复建议" 按钮
|
||||
│
|
||||
▼
|
||||
POST /ai/vul_suggestion ──→ 返回 AI 生成的修复建议
|
||||
│
|
||||
▼
|
||||
弹窗展示:漏洞特性 + 漏洞描述 + 升级版本 + 修复建议列表
|
||||
```
|
||||
|
||||
### 涉及的组件
|
||||
|
||||
| 组件 | 位置 | 做什么 |
|
||||
|------|------|--------|
|
||||
| **AIRepair 主页** | `src/views/Jyh/AIRepair/` | 主页面,展示漏洞列表 + AI 修复建议面板 |
|
||||
| **Panel** | `src/components/AIRepair/` | 可折叠展开面板,带 `max-height` 动画过渡 |
|
||||
| **Table** | `src/components/AIRepair/` | 漏洞表格 + "AI修复建议"按钮 + 弹窗展示 AI 建议 |
|
||||
|
||||
### 技术要点
|
||||
|
||||
- 对接**金银湖大模型**的 `/ai/vul_suggestion` 接口,传入组件名、版本号、CVE 编号,返回结构化的修复建议(漏洞特性、描述、升级版本、修复建议列表)
|
||||
- 修复建议以**结构化 JSON** 返回,前端用列表形式渲染
|
||||
- Panel 组件使用了 `requestAnimationFrame` + `scrollHeight` 实现平滑折叠动画
|
||||
- 该功能在 **3 个父页面**中以 Tab 形式嵌入(版本详情页、AI Home 开源详情页、代码质量页)
|
||||
|
||||
### 后续详细文档
|
||||
|
||||
> → [[经历2-TcodeAI助手辅助修复详解]] ✅ 已完成
|
||||
|
||||
---
|
||||
|
||||
## 四、经历3:API 接口前后端集成
|
||||
|
||||
### 做了什么
|
||||
|
||||
协作设计了可信态势感知平台的 API 接口,完成了 **50+ 数据接口**的前后端集成,涵盖态势感知数据看板、仓库管理、组织管理、用户管理、AI 对话、合并请求、Issue 跟踪等多个业务模块。
|
||||
|
||||
### 整体规模
|
||||
|
||||
| 数据 | 数值 |
|
||||
|------|------|
|
||||
| API 函数总数 | **641 个** |
|
||||
| API 文件数 | **29 个** |
|
||||
| 金银湖(JYH)相关 API | **106 个**(situation.ts 50 + index.ts 45 + home.ts 5 + auth.ts 3 + scanCenter.ts 3) |
|
||||
| 态势感知看板接口 | **50+ 个**(三大页面,覆盖全球态势、开源生态、武汉本地生态) |
|
||||
|
||||
### 请求基础设施
|
||||
|
||||
```
|
||||
请求发出
|
||||
│
|
||||
├── 请求拦截器
|
||||
│ ├── Token 注入(DP_TOKEN + DP_REFRESH_TOKEN)
|
||||
│ ├── 页面级 Header 附加(标题、仓库ID、来源、UTM)
|
||||
│ └── URL 前缀重写(passport /uc 前缀)
|
||||
│
|
||||
├── 数据传输
|
||||
│ ├── AES-128-CBC 加密/解密(密钥 + IV 硬编码)
|
||||
│ └── 标准 POST/GET,部分接口使用 FormData 上传
|
||||
│
|
||||
└── 响应拦截器
|
||||
├── 解密响应数据
|
||||
├── HTTP 状态码处理(400/401/403/408/500/502/504)
|
||||
├── Token 过期自动刷新 + 请求队列重放
|
||||
└── API 缓存降级(IndexedDB 缓存失败兜底)
|
||||
```
|
||||
|
||||
### 关键模块
|
||||
|
||||
| 模块 | 文件 | 核心接口 |
|
||||
|------|------|---------|
|
||||
| **态势感知看板** | `jyh/situation.ts`(50 端点) | 威胁地图、CVE 趋势、组件排行、漏洞分布、生态健康度等 |
|
||||
| **仓库管理** | `repo/index.ts`(161 端点) | 仓库 CRUD、分支/标签、Webhook、文件管理、Wiki、Star/Fork |
|
||||
| **合并请求** | `merge/index.ts`(62 端点) | MR 创建/审查、差异对比、代码评审、门禁检查 |
|
||||
| **AI 大模型** | `jyh/index.ts`(45 端点) | 对话创建、消息收发、历史管理、推荐问题、修复建议 |
|
||||
| **组织管理** | `org/index.ts`(55 端点) | 组织 CRUD、成员管理、主页信息、CLA 管理 |
|
||||
| **用户管理** | `user/index.ts`(55+ 端点) | 登录注册、OAuth、个人资料、SSH 密钥、Token 管理 |
|
||||
| **讨论系统** | `discussion/index.ts`(50 端点) | 讨论 CRUD、分类、评论、投票、排行榜 |
|
||||
|
||||
### 技术要点
|
||||
|
||||
- **AES 加密**:敏感数据在传输层使用 AES-128-CBC 加密(密钥 `mXzfCSPBKmEA8aLq`,IV `tbeJJLC6dZQXXtWr`)
|
||||
- **Token 自动刷新**:401 响应触发自动刷新,并发请求排队等待,刷新成功后统一重发
|
||||
- **错误降级**:`reqCatch` / `reqCatchV2` 包装函数,API 失败时自动捕获错误并通过事件总线通知;部分接口有硬编码兜底数据
|
||||
- **自定义错误处理**:支持 `customError: true` 参数跳过默认错误提示,由调用方自行处理
|
||||
- **环境切换**:通过 Vite 环境变量区分开发/测试/生产环境 API 地址
|
||||
|
||||
### 后续详细文档
|
||||
|
||||
> → [[经历3-API接口前后端集成详解]] ✅ 已完成
|
||||
|
||||
---
|
||||
|
||||
## 五、三条经历的面试定位
|
||||
|
||||
| 经历 | 展示什么能力 | 面试重点 |
|
||||
|------|------------|---------|
|
||||
| **经历1(风险监测)** | 数据可视化能力、ECharts 实战、复杂图表组件开发 | ECharts 使用经验、地图图表、大数据图表性能 |
|
||||
| **经历2(AI修复)** | AI 能力集成、前后端协作、组件化设计 | 大模型接入方式、结构化响应处理、组件复用 |
|
||||
| **经历3(API集成)** | 工程化能力、安全设计、大规模接口管理 | 请求拦截器、加密方案、Token 刷新、错误处理 |
|
||||
|
||||
**一句话概括**:
|
||||
> "我在实习中从三个层面参与了平台建设——前端展示层(数据可视化组件)、AI 智能层(大模型集成)、数据通信层(API 设计与集成),形成了比较完整的项目参与度。"
|
||||
|
||||
---
|
||||
|
||||
## 六、涉及的源码文件总览
|
||||
|
||||
### 经历1:风险监测模块
|
||||
|
||||
| 做什么 | 文件在哪 |
|
||||
|--------|----------|
|
||||
| 态势感知主页面 | `src/views/Jyh/security/index.vue` |
|
||||
| 全球威胁地图 | `src/views/Jyh/security/components/ThreatIntelMap.vue` |
|
||||
| 中国安全地图 | `src/views/Jyh/security/components/ChinaSecurityMap.vue` |
|
||||
| CVE 趋势图 | `src/views/Jyh/security/components/CveTrendChart.vue` |
|
||||
| 高危组件排行 | `src/views/Jyh/security/components/HighRiskComponentRank.vue` |
|
||||
| 漏洞严重性分布 | `src/views/Jyh/security/components/VulnerabilitySeverityChart.vue` |
|
||||
| 语言漏洞趋势 | `src/views/Jyh/security/components/VulnerabilityLanguageChart.vue` |
|
||||
| 语言安全散点图 | `src/views/Jyh/security/components/ScatterChart.vue` |
|
||||
| 行业分布饼图 | `src/views/Jyh/security/components/IndustryDistribution.vue` |
|
||||
| 情报动态流 | `src/views/Jyh/security/components/IntelligenceFeed.vue` |
|
||||
| 统计卡片 | `src/views/Jyh/security/StatsGlass.vue` |
|
||||
| 态势 API(50 端点) | `src/api/jyh/situation.ts` |
|
||||
| 威胁情报库 | `src/views/Jyh/ThreatIntelligence/index.vue` |
|
||||
| 漏洞数据库 | `src/views/Jyh/VulnerabilityDatabase/index.vue` |
|
||||
|
||||
### 经历2:AI 修复功能
|
||||
|
||||
| 做什么 | 文件在哪 |
|
||||
|--------|----------|
|
||||
| AI 修复主页面 | `src/views/Jyh/AIRepair/index.vue` |
|
||||
| 可折叠面板组件 | `src/components/AIRepair/Panel.vue` |
|
||||
| 漏洞表格 + AI 建议弹窗 | `src/components/AIRepair/Table.vue` |
|
||||
| AI Home 中的修复 | `src/views/Jyh/AI/Home/components/OssDetail/AIRepair/index.vue` |
|
||||
| AI 修复 API | `src/api/jyh/index.ts`(remediationSearchRemediations, getVulSuggestion) |
|
||||
| 版本详情(嵌入位置) | `src/views/Jyh/Version/Detail/index.vue` |
|
||||
|
||||
### 经历3:API 集成
|
||||
|
||||
| 做什么 | 文件在哪 |
|
||||
|--------|----------|
|
||||
| 请求核心基础设施 | `src/utils/request.ts`(Axios 实例、拦截器、加密、Token 刷新) |
|
||||
| 态势感知看板 API | `src/api/jyh/situation.ts`(50 端点) |
|
||||
| 金银湖核心 API | `src/api/jyh/index.ts`(45 端点) |
|
||||
| 仓库管理 API | `src/api/repo/index.ts`(161 端点) |
|
||||
| 组织管理 API | `src/api/org/index.ts`(55 端点) |
|
||||
| 用户管理 API | `src/api/user/index.ts`(55+ 端点) |
|
||||
| 错误捕获包装 | `src/utils/catch.ts`(reqCatch / reqCatchV2) |
|
||||
| 状态码处理 | `src/utils/status.ts`(dealWarning) |
|
||||
| 缓存降级系统 | `src/utils/degradeInterceptor.ts` |
|
||||
| 加密配置 | `src/utils/request.ts`(AES-CBC 加密) |
|
||||
380
实习讲解/经历1-全球风险监测模块详解.md
Normal file
380
实习讲解/经历1-全球风险监测模块详解.md
Normal file
@@ -0,0 +1,380 @@
|
||||
# 全球风险监测模块 — 面试版
|
||||
|
||||
> 简历原话:**"参与开发全球风险监测模块,实现威胁情报地图、CVE趋势分析、高危组件排行等10+数据可视化组件"**
|
||||
>
|
||||
> 这篇文档帮你理解这个模块到底做了什么、怎么做的,以及面试时怎么讲。
|
||||
|
||||
---
|
||||
|
||||
## 一、先搞清楚:这个模块是什么?
|
||||
|
||||
全球风险监测模块是一个完整的数据可视化大屏,路由为 `/security`,页面标题为"全球开源风险态势感知监控中心"。页面上展示了 **10+ 个 ECharts 图表组件**,从全球威胁地图到高危组件排行、从 CVE 趋势到编程语言安全态势,覆盖了威胁情报的多个维度。
|
||||
|
||||
**一句话概括**:我用 ECharts 6.x 实现了一个安全态势数据可视化大屏,包含 10+ 个不同类型的图表组件(地图、柱状图、折线图、饼图、面积图、散点图等),展示了全球开源威胁情报的多个维度。
|
||||
|
||||
---
|
||||
|
||||
## 二、页面长什么样?(整体布局)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ StatsGlass(统计卡片:4 项全球汇总指标) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ 🛡️ ThreatIntelMap(全球威胁情报地图) │ │
|
||||
│ │ 世界地图热力 + 关键节点散点 + 实时警报 │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │IndustryDist │ │HighRisk │ │Intelligence │ │
|
||||
│ │行业分布饼图 │ │高危组件Top10 │ │实时情报动态流 │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ CveTrendChart(CVE 月度趋势 柱状图+折线图) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ VulnerabilityLanguageChart(12种语言漏洞趋势面积图) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ VulnerabilitySeverityChart(漏洞等级堆叠柱状图) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ ScatterChart(编程语言安全态势气泡散点图) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
页面使用暗色科技风背景(`#020617`),每个图表卡片有毛玻璃效果(`backdrop-filter: blur`),鼠标悬停有上浮动画。
|
||||
|
||||
---
|
||||
|
||||
## 三、10+ 个组件一览
|
||||
|
||||
| 组件 | 图表类型 | 数据来源 | 直观展示什么 |
|
||||
|------|---------|---------|------------|
|
||||
| **ThreatIntelMap** | 世界地图 + 热力 + 散点 | `/api/v1/page1/map/mapData` 等 4 个接口 | 全球威胁分布热力图,北京/上海/华盛顿等 6 个关键节点,实时漏洞类型分布面板 |
|
||||
| **ChinaSecurityMap** | 中国地图 + 攻击路径 | 懒加载中国 GeoJSON | 各省威胁热力、安全监测节点、城市间攻击路径动画 |
|
||||
| **CveTrendChart** | 柱状图 + 折线图(双轴) | `/api/v1/page1/cveData/global` | CVE 数量柱状图 + 环比增长率折线图,支持全球/区域切换 |
|
||||
| **HighRiskComponentRank** | 横向柱状图 | `/api/v1/page1/highRiskComponent` | Top 10 高危开源组件,按 CVSS 评分排序,颜色标识严重程度 |
|
||||
| **VulnerabilitySeverityChart** | 堆叠柱状图 | `/api/v1/page1/vulnerabilitySeverity` | 高/中/低危漏洞数量按季度堆叠分布(2024Q1-2025Q4) |
|
||||
| **VulnerabilityLanguageChart** | 堆叠面积图 | `/api/v1/page1/languageTrend` | 12 种编程语言 2017-2024 年的漏洞趋势变化 |
|
||||
| **ScatterChart** | 气泡散点图 | `/api/v1/page1/scatterData` | 编程语言安全态势:X 轴代码活跃度、Y 轴漏洞密度、气泡大小=漏洞总数 |
|
||||
| **IndustryDistribution** | 环形饼图 | `/api/v1/page1/industryDistribution` | 开源风险在 AI、云计算、大数据等 8 大行业的分布占比 |
|
||||
| **IntelligenceFeed** | 自动滚动列表 | `/api/v1/page1/feedList` | 实时安全情报流,带类型标签(CISA/Poisoning/CNVD/GitHub) |
|
||||
| **StatsGlass** | 毛玻璃统计卡片 | `/api/v1/page1/overviewData` | 4 项全球汇总指标(企业数、高校数、社区活跃度、项目数) |
|
||||
|
||||
除了以上 10 个独立组件,主页面 `index.vue` 中还有 **5 个内联 ECharts 图表**:
|
||||
|
||||
| 内联图表 | 图表类型 | 展示内容 |
|
||||
|---------|---------|---------|
|
||||
| 高校开源参与分布 | 环形饼图 | 华中科大、武大等高校参与度 |
|
||||
| 社区区域分布 | 柱状图 | 武昌区、洪山区等社区分布 |
|
||||
| OSS Compass 排行 | 横向柱状图 | OpenHarmony、MindSpore 等开源项目排行 |
|
||||
| 开发者排行榜 | 横向柱状图 | 武汉开源开发者 Top 10 |
|
||||
| 语言技术趋势 | 多系列折线图 | Java、Python、Rust、仓颉等 5 种语言的趋势 |
|
||||
|
||||
**合计:15+ 个图表组件。**
|
||||
|
||||
---
|
||||
|
||||
## 四、怎么实现的?(面试核心)
|
||||
|
||||
所有图表组件遵循统一的 **三步模式**:获取数据 → 初始化图表 → 清理销毁。
|
||||
|
||||
### 4.1 统一的开发模式(每个组件都一样)
|
||||
|
||||
```typescript
|
||||
// 以 HighRiskComponentRank 为例
|
||||
import * as echarts from 'echarts';
|
||||
import { highRiskComponentPage1 } from '@/api/jyh/situation';
|
||||
|
||||
// ====== 步骤 1:获取数据 ======
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await highRiskComponentPage1();
|
||||
if (response.data.code === 200) {
|
||||
componentData.value = response.data.data; // ✅ 成功:用后端数据
|
||||
} else {
|
||||
componentData.value = [...defaultData]; // ⚠️ 失败:用兜底数据
|
||||
}
|
||||
} catch (error) {
|
||||
componentData.value = [...defaultData]; // ❌ 异常:用兜底数据
|
||||
}
|
||||
};
|
||||
|
||||
// ====== 步骤 2:初始化图表 ======
|
||||
const initChart = () => {
|
||||
if (chartInstance) chartInstance.dispose(); // 先销毁旧实例
|
||||
chartInstance = echarts.init(chartRef.value); // 创建新实例
|
||||
chartInstance.setOption({
|
||||
// ... 图表配置(tooltip、grid、xAxis、yAxis、series 等)
|
||||
});
|
||||
window.addEventListener('resize', handleResize); // 响应窗口大小变化
|
||||
};
|
||||
|
||||
// ====== 步骤 3:清理销毁 ======
|
||||
onUnmounted(() => {
|
||||
if (chartInstance) chartInstance.dispose(); // 组件卸载时销毁,防止内存泄漏
|
||||
window.removeEventListener('resize', handleResize);
|
||||
});
|
||||
```
|
||||
|
||||
**面试话术**:
|
||||
> "所有图表组件遵循统一的开发模式:第一,通过 API 获取数据,接口失败时自动降级为预设的兜底数据,保证图表不会白屏;第二,使用 echarts.init 初始化图表,通过 setOption 配置图表样式和交互;第三,组件卸载时调用 dispose 销毁实例,移除 resize 监听,防止内存泄漏。切换数据时会先 dispose 旧实例再重新 init,确保图表完全刷新。"
|
||||
|
||||
### 4.2 全球威胁情报地图(技术含量最高)
|
||||
|
||||
ThreatIntelMap 是整个模块最复杂的组件,综合使用了多种 ECharts 地图能力:
|
||||
|
||||
```typescript
|
||||
// ThreatIntelMap.vue — 核心配置(简化版)
|
||||
echarts.registerMap('world', worldJson); // 注册世界地图 GeoJSON
|
||||
|
||||
const option = {
|
||||
// 1. 视觉映射:热力渐变
|
||||
visualMap: {
|
||||
min: 0, max: 100,
|
||||
inRange: { color: ['#1e3c72', '#2a5298', '#24b6d8', '#facc15', '#ef4444'] }
|
||||
},
|
||||
// 2. 地理坐标系:世界地图
|
||||
geo: {
|
||||
map: 'world', roam: true, zoom: 1.2,
|
||||
itemStyle: { areaColor: '#0f172a', borderColor: '#1e293b' }
|
||||
},
|
||||
// 3. 三个数据系列
|
||||
series: [
|
||||
{
|
||||
name: 'Threat Distribution',
|
||||
type: 'map', // ← 地图热力层
|
||||
geoIndex: 0,
|
||||
data: mapData // 国家→风险值
|
||||
},
|
||||
{
|
||||
name: 'Key Nodes',
|
||||
type: 'effectScatter', // ← 涟漪散点层(关键安全节点)
|
||||
coordinateSystem: 'geo',
|
||||
data: scatterData, // 北京、上海、华盛顿等 6 个节点
|
||||
rippleEffect: { scale: 3 }
|
||||
},
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
同时在地图叠加层渲染了三个信息面板:
|
||||
- **左侧面板**:漏洞类型分布 Top 5(XSS 32.1%、SQL 注入 11.9% 等),带进度条动画
|
||||
- **右侧面板**:威胁情报地域排行(美国 435,202 次、印度 252,054 次等)
|
||||
- **底部卡片**:实时安全警报(自动轮播,3.5 秒切换一条,带脉冲动画)
|
||||
|
||||
**面试话术**:
|
||||
> "全球威胁地图是整个模块最复杂的组件。它用到了 ECharts 的地图系列 + effectScatter 涟漪散点图的组合,在 GeoJSON 世界地图上叠加了两层数据——国家热力层展示威胁分布,散点层标记 6 个关键安全节点。地图上还有三个信息面板——漏洞类型分布、地域排行、实时警报。世界地图的 GeoJSON 文件通过动态 import 懒加载,只在用户进入这个页面时才下载,不打包进主 bundle。"
|
||||
|
||||
### 4.3 CVE 月度趋势 — 双轴组合图
|
||||
|
||||
```typescript
|
||||
// CveTrendChart.vue — 双 Y 轴组合图(柱状图 + 折线图)
|
||||
const option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
// 两个 Y 轴:左边 CVE 数量,右边增长率百分比
|
||||
yAxis: [
|
||||
{ type: 'value', name: 'CVE数量', position: 'left' }, // ← 对应柱状图
|
||||
{ type: 'value', name: '环比增长率(%)', position: 'right' } // ← 对应折线图
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'CVE数量',
|
||||
type: 'bar', // ← 柱状图,左轴
|
||||
data: cveCount,
|
||||
itemStyle: { color: new echarts.graphic.LinearGradient(...) } // 渐变色
|
||||
},
|
||||
{
|
||||
name: '环比增长率',
|
||||
type: 'line', // ← 折线图,右轴
|
||||
yAxisIndex: 1, // 使用右轴
|
||||
data: acceleration,
|
||||
smooth: true, // 平滑曲线
|
||||
itemStyle: { color: '#ef4444' } // 红色
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
支持通过按钮切换"全球视图"和"区域视图",切换时重新请求对应的 API 接口并重新渲染图表。
|
||||
|
||||
### 4.4 高危组件 Top 10 — 横向柱状图 + CVSS 颜色标识
|
||||
|
||||
```typescript
|
||||
// HighRiskComponentRank.vue — 颜色随 CVSS 评分变化
|
||||
series: [{
|
||||
type: 'bar',
|
||||
data: cvssScores,
|
||||
itemStyle: {
|
||||
color: (params) => {
|
||||
if (params.value >= 9.0) return '#ef4444'; // 红色 — 严重
|
||||
if (params.value >= 7.0) return '#f97316'; // 橙色 — 高危
|
||||
if (params.value >= 4.0) return '#eab308'; // 黄色 — 中危
|
||||
return '#22c55e'; // 绿色 — 低危
|
||||
}
|
||||
},
|
||||
label: { show: true, position: 'right' } // 数值标签显示在柱子右侧
|
||||
}]
|
||||
```
|
||||
|
||||
Y 轴设置 `inverse: true`,让 CVSS 评分最高的组件显示在最上面。
|
||||
|
||||
### 4.5 漏洞等级分布 — 堆叠柱状图
|
||||
|
||||
```typescript
|
||||
// VulnerabilitySeverityChart.vue — 三个系列堆叠
|
||||
series: [
|
||||
{ name: '高危漏洞', type: 'bar', stack: 'total', color: '#FF4D4F', data: [...] },
|
||||
{ name: '中危漏洞', type: 'bar', stack: 'total', color: '#FAAD14', data: [...] },
|
||||
{ name: '低危漏洞', type: 'bar', stack: 'total', color: '#36CFC9', data: [...] },
|
||||
]
|
||||
// 三个系列的 stack 值都是 'total',ECharts 会自动堆叠
|
||||
// tooltip 中计算每个等级占总数的百分比
|
||||
```
|
||||
|
||||
### 4.6 三个重要的设计细节
|
||||
|
||||
#### 细节 1:每个组件都有 API 失败兜底
|
||||
|
||||
```typescript
|
||||
// 所有图表组件的共同特点:API 失败时用硬编码数据兜底
|
||||
try {
|
||||
const res = await apiFunction();
|
||||
if (res.data.code === 200) {
|
||||
chartData.value = res.data.data; // ✅ 后端数据
|
||||
} else {
|
||||
chartData.value = DEFAULT_DATA; // ⚠️ 兜底数据
|
||||
}
|
||||
} catch {
|
||||
chartData.value = DEFAULT_DATA; // ❌ 网络异常,兜底数据
|
||||
}
|
||||
```
|
||||
|
||||
**为什么这样设计?** 态势大屏在演示时不能白屏。即使后端挂了,至少展示兜底数据让页面是完整的。
|
||||
|
||||
#### 细节 2:图表实例的 dispose → init 生命周期
|
||||
|
||||
```typescript
|
||||
// 切换数据时:先销毁旧实例,再创建新实例
|
||||
if (chartInstance) chartInstance.dispose(); // 销毁旧实例(释放内存)
|
||||
chartInstance = echarts.init(el); // 创建新实例
|
||||
chartInstance.setOption(option); // 渲染新数据
|
||||
|
||||
// 组件卸载时:销毁实例 + 移除监听
|
||||
onUnmounted(() => {
|
||||
chartInstance?.dispose(); // 防止内存泄漏
|
||||
window.removeEventListener('resize', handler);
|
||||
});
|
||||
```
|
||||
|
||||
**为什么不用 myChart.setOption() 更新?** 当数据维度变化时(如 CVE 趋势图切换全球/区域视图、X 轴月份数变化),直接 setOption 会有残留配置。先 dispose 再 init 是最稳妥的做法。
|
||||
|
||||
#### 细节 3:地图数据的懒加载
|
||||
|
||||
```typescript
|
||||
// 世界地图 GeoJSON 通过 import 在组件内引用
|
||||
import worldJson from './world.json'; // 只在 ThreatIntelMap 组件被加载时才下载
|
||||
|
||||
// 中国地图 GeoJSON 通过动态函数加载(utils/mapLoader.js)
|
||||
export const loadChinaMap = async () => {
|
||||
await import('/china.js'); // 只在进入中国地图页面时才下载(几百 KB)
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、完整的数据流
|
||||
|
||||
```
|
||||
页面加载 (/security)
|
||||
│
|
||||
├──→ StatsGlass 调 overviewDataPage1 ← /api/v1/page1/overviewData
|
||||
├──→ ThreatIntelMap 调 4 个 map API ← /api/v1/page1/map/*
|
||||
├──→ IndustryDistribution 调 industryDistributionPage1 ← /api/v1/page1/industryDistribution
|
||||
├──→ HighRiskComponentRank 调 highRiskComponentPage1 ← /api/v1/page1/highRiskComponent
|
||||
├──→ IntelligenceFeed 调 feedListPage1 ← /api/v1/page1/feedList
|
||||
├──→ CveTrendChart 调 cveDataGlobal + regional ← /api/v1/page1/cveData/*
|
||||
├──→ VulnerabilityLang 调 languageTrendPage1 ← /api/v1/page1/languageTrend
|
||||
├──→ VulnerabilitySev 调 vulnerabilitySeverityPage1 ← /api/v1/page1/vulnerabilitySeverity
|
||||
├──→ ScatterChart 调 scatterDataPage1 ← /api/v1/page1/scatterData
|
||||
└──→ 5 个内联图表 硬编码数据(武汉市开源生态展示)
|
||||
```
|
||||
|
||||
**共 13 个后端 API 接口**,全部以 `/api/v1/page1/` 为前缀,定义在 `src/api/jyh/situation.ts` 中。
|
||||
|
||||
---
|
||||
|
||||
## 六、面试问答准备
|
||||
|
||||
### Q1:"参与开发全球风险监测模块"具体做了什么?
|
||||
|
||||
> 我参与开发了全球开源风险态势感知监控中心这个大屏页面,用 ECharts 6.x 实现了 10+ 个数据可视化组件。具体包括:全球威胁情报地图(世界地图热力 + 关键节点散点 + 实时警报面板)、CVE 月度趋势图(双轴柱状图+折线图,支持全球/区域切换)、高危组件 Top 10 排行(横向柱状图,按 CVSS 评分颜色标识)、漏洞等级分布(高/中/低危堆叠柱状图)、编程语言漏洞趋势面积图(12 种语言 2017-2024)、编程语言安全态势气泡图(活跃度 vs 漏洞密度)等。页面采用暗色科技风主题,毛玻璃卡片布局,每个组件都有 API 失败兜底数据。
|
||||
|
||||
### Q2:10+ 个图表组件,代码怎么组织的?
|
||||
|
||||
> 每个图表都是一个独立的 Vue SFC 组件(如 ThreatIntelMap.vue、CveTrendChart.vue),在主页面 index.vue 中通过 import 引入并组合布局。所有组件遵循统一的开发模式:获取数据(调 API,失败用兜底数据)→ 初始化图表(echarts.init + setOption)→ 清理销毁(dispose + 移除监听)。组件之间互不依赖,可以独立开发和调试。
|
||||
|
||||
### Q3:地图是怎么做的?
|
||||
|
||||
> 我用 ECharts 的 map 系列实现。世界地图使用 GeoJSON 数据(world.json),通过 echarts.registerMap 注册后在地理坐标系上渲染。地图上叠加了两层数据:map 系列展示国家热力分布(通过 visualMap 控制颜色渐变),effectScatter 系列展示关键安全节点(北京、上海、华盛顿等 6 个点,带涟漪动画)。还在地图四个角叠加了信息面板——漏洞类型分布、地域排行、实时警报。
|
||||
|
||||
### Q4:图表性能怎么考虑的?
|
||||
|
||||
> 三个方面的处理:第一,地图 GeoJSON 文件(几百 KB)使用懒加载,只在 ThreatIntelMap 组件渲染时才下载;第二,每个图表组件在卸载时调用 echartsInstance.dispose() 销毁实例并移除 resize 监听,防止内存泄漏;第三,图表切换数据时(如 CVE 全球/区域切换),先 dispose 再重新 init,避免 setOption 合并残留配置导致的问题。
|
||||
|
||||
### Q5:如果后端 API 挂了,页面会白屏吗?
|
||||
|
||||
> 不会。每个图表组件都设计了数据降级策略——API 请求失败或返回异常时,自动使用预设的兜底数据渲染。比如高危组件 Top 10 的兜底数据包含了 Log4j2(9.8)、Struts2(9.7)、OpenSSL(9.6)等真实的公开漏洞数据。这样即使后端挂了,大屏依然能完整展示,不影响演示效果。
|
||||
|
||||
### Q6:ECharts 的 setOption 和 dispose+init 有什么区别?为什么你的组件用 dispose+init?
|
||||
|
||||
> setOption 适合增量更新——数据变了但图表类型、轴配置不变时,用 setOption 合并新配置即可,不会闪烁。但我的组件有些场景下图表维度会变化(比如 CVE 趋势图切换全球/区域时,数据量和走势完全不同),直接 setOption 可能残留旧配置。所以统一采用 dispose + init 的方式,确保每次都是全新渲染。代价是有短暂闪烁,但数据一致性能保证。
|
||||
|
||||
### Q7:你用到了哪些 ECharts 图表类型?
|
||||
|
||||
> 地图(map)、涟漪散点图(effectScatter)、柱状图(bar,含堆叠柱状图)、折线图(line)、饼图(pie/环形图)、面积图(area/堆叠面积图)、散点图/气泡图(scatter)、热力 visualMap。总共大概 7-8 种图表类型的组合使用。
|
||||
|
||||
---
|
||||
|
||||
## 七、关键数字(面试时用)
|
||||
|
||||
| 数据 | 数字 |
|
||||
|------|------|
|
||||
| 独立图表组件数 | 10 个(import 引入的子组件) |
|
||||
| 内联图表数 | 5 个(index.vue 中直接写的) |
|
||||
| 图表总数 | **15+** 个 |
|
||||
| ECharts 图表类型 | **8 种**(map、effectScatter、bar、line、pie、area、scatter、visualMap) |
|
||||
| 后端 API 接口 | **13 个**(`/api/v1/page1/*`) |
|
||||
| API 接口文件 | `src/api/jyh/situation.ts`(50 个端点,其中 13 个属于此模块) |
|
||||
| 地图 GeoJSON 文件 | 2 个(world.json + china.js) |
|
||||
| 暗色主题背景色 | `#020617` |
|
||||
| 毛玻璃卡片效果 | `backdrop-filter: blur(10px)` |
|
||||
|
||||
---
|
||||
|
||||
## 八、涉及的源码文件(需要看的时候查)
|
||||
|
||||
| 做什么 | 文件在哪 |
|
||||
|--------|----------|
|
||||
| 主页面(布局 + 5 个内联图表) | `src/views/Jyh/security/index.vue` |
|
||||
| 全球威胁情报地图 | `src/views/Jyh/security/components/ThreatIntelMap.vue` |
|
||||
| 中国安全态势地图 | `src/views/Jyh/security/components/ChinaSecurityMap.vue` |
|
||||
| CVE 月度趋势图 | `src/views/Jyh/security/components/CveTrendChart.vue` |
|
||||
| 高危组件 Top 10 排行 | `src/views/Jyh/security/components/HighRiskComponentRank.vue` |
|
||||
| 漏洞等级分布图 | `src/views/Jyh/security/components/VulnerabilitySeverityChart.vue` |
|
||||
| 编程语言漏洞趋势图 | `src/views/Jyh/security/components/VulnerabilityLanguageChart.vue` |
|
||||
| 编程语言安全态势气泡图 | `src/views/Jyh/security/components/ScatterChart.vue` |
|
||||
| 行业分布饼图 | `src/views/Jyh/security/components/IndustryDistribution.vue` |
|
||||
| 实时情报动态流 | `src/views/Jyh/security/components/IntelligenceFeed.vue` |
|
||||
| 统计卡片 | `src/views/Jyh/security/StatsGlass.vue` |
|
||||
| 世界地图 GeoJSON | `src/views/Jyh/security/components/world.json` |
|
||||
| 所有态势感知 API | `src/api/jyh/situation.ts` |
|
||||
| 关联页面:威胁情报库 | `src/views/Jyh/ThreatIntelligence/index.vue` |
|
||||
| 关联页面:漏洞数据库 | `src/views/Jyh/VulnerabilityDatabase/index.vue` |
|
||||
314
实习讲解/经历2-TcodeAI助手辅助修复详解.md
Normal file
314
实习讲解/经历2-TcodeAI助手辅助修复详解.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# TcodeAI 助手辅助修复功能 — 面试版
|
||||
|
||||
> 简历原话:**"参与开发TcodeAI助手辅助修复功能,集成金银湖大模型能力,提供智能漏洞修复建议"**
|
||||
>
|
||||
> 这篇文档帮你理解这个功能到底做了什么、怎么做的,以及面试时怎么讲。
|
||||
|
||||
---
|
||||
|
||||
## 一、先搞清楚:这个功能是什么?
|
||||
|
||||
在可信态势感知平台中,用户查看某个软件版本时,平台会扫描该版本依赖的开源组件,列出其中存在的已知漏洞。TcodeAI 助手辅助修复功能的作用就是——**对每个漏洞生成一份 AI 修复建议**,告诉用户这个漏洞有什么特征、怎么描述、建议升级到什么版本、具体怎么修。
|
||||
|
||||
**一句话概括**:我给平台接入了金银湖大模型的智能修复能力,用户点一下"AI修复建议"按钮,就能看到模型生成的漏洞分析 + 升级方案 + 修复步骤。
|
||||
|
||||
---
|
||||
|
||||
## 二、功能长什么样?(用户视角)
|
||||
|
||||
```
|
||||
用户进入软件版本详情页
|
||||
│
|
||||
▼
|
||||
切换到 "AI修复建议" Tab
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ AI修复建议说明(功能介绍横幅) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ 🔴 严重 Log4j2 [展开 ▼] │ │
|
||||
│ │ 安全问题 3 升级版本 2.14.0 → 2.17.1 │ │
|
||||
│ ├───────────────────────────────────────────────────────┤ │
|
||||
│ │ (展开后显示漏洞列表表格) │ │
|
||||
│ │ ┌──────────┬──────────┬──────────┬──────┬──────────┐ │ │
|
||||
│ │ │ 问题编号 │ 问题类型 │ CWE编号 │ 分值 │ 操作 │ │ │
|
||||
│ │ ├──────────┼──────────┼──────────┼──────┼──────────┤ │ │
|
||||
│ │ │CVE-2021..│ RCE │ CWE-502 │ 9.8 │[AI修复] │ │ │
|
||||
│ │ │CVE-2021..│ DoS │ CWE-400 │ 7.5 │[AI修复] │ │ │
|
||||
│ │ └──────────┴──────────┴──────────┴──────┴──────────┘ │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ 🔴 严重 Spring Framework [展开 ▼] │ │
|
||||
│ │ 安全问题 2 升级版本 5.3.26 → 5.3.31 │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ (点击 "AI修复建议" 按钮后弹出弹窗) │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ AI修复建议 [弹窗] │ │
|
||||
│ │ ┌─────────────────────────────────────────────────┐ │ │
|
||||
│ │ │ 漏洞特性:远程代码执行,攻击者可构造恶意数据包... │ │ │
|
||||
│ │ │ 漏洞描述:Apache Log4j2 存在 JNDI 注入漏洞... │ │ │
|
||||
│ │ │ 升级版本:2.17.1 │ │ │
|
||||
│ │ │ 🤖 AI修复建议: │ │ │
|
||||
│ │ │ • 将 Log4j2 版本升级至 2.17.1 或更高版本 │ │ │
|
||||
│ │ │ • 若无法升级,设置 log4j2.formatMsgNoLookups=true│ │ │
|
||||
│ │ │ • 检查项目中是否有自定义的 Lookup 插件... │ │ │
|
||||
│ │ └─────────────────────────────────────────────────┘ │ │
|
||||
│ │ [确定] [取消] │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、怎么实现的?(面试核心)
|
||||
|
||||
### 3.1 三个组件的协作关系
|
||||
|
||||
这个功能由三个组件构成:
|
||||
|
||||
```
|
||||
AIRepair/index.vue(主页面)
|
||||
│
|
||||
├──→ 调用 /api/v1/repo/repair/info 获取漏洞数据
|
||||
│
|
||||
├──→ Panel.vue(可折叠面板组件)
|
||||
│ 每个受影响的库一个面板,展示库名、版本、升级路径
|
||||
│ 点击 "展开/收起" 控制面板折叠
|
||||
│
|
||||
└──→ Table.vue(漏洞表格 + AI 建议弹窗)
|
||||
展示该库下的漏洞列表(CVE编号、类型、CVSS评分)
|
||||
点击 "AI修复建议" → 调用 /ai/vul_suggestion → 弹窗展示 AI 建议
|
||||
```
|
||||
|
||||
### 3.2 第一步:获取漏洞列表(AIRepair/index.vue)
|
||||
|
||||
```typescript
|
||||
// views/Jyh/AIRepair/index.vue(简化版)
|
||||
const tableData = ref([]);
|
||||
const pager = ref({ total: 10, pageIndex: 1, pageSize: 10 });
|
||||
|
||||
// 页面加载时调后端 API 获取受漏洞影响的组件列表
|
||||
const fetchVulnList = async () => {
|
||||
const { data } = await remediationSearchRemediations({
|
||||
softwareId: propsData.versionId, // 当前查看的软件版本 ID
|
||||
current: pager.value.pageIndex,
|
||||
size: pager.value.pageSize
|
||||
});
|
||||
|
||||
if (data.data.code === 200) {
|
||||
// 数据格式:每个元素是一个受影响的库
|
||||
// { libraryName, currentVersion, recommendedVersion, vulnerabilities: [...] }
|
||||
tableData.value = data?.data?.data?.records || [];
|
||||
pager.value.total = data?.data?.data?.total || 0;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => { fetchVulnList(); });
|
||||
```
|
||||
|
||||
**API 接口**:`POST /api/v1/repo/repair/info`,参数 `{ softwareId, current, size }`。
|
||||
|
||||
### 3.3 第二步:可折叠面板(Panel.vue)
|
||||
|
||||
```vue
|
||||
<!-- components/AIRepair/Panel.vue — 可折叠面板 -->
|
||||
<template>
|
||||
<!-- 头部:始终可见 -->
|
||||
<div>
|
||||
<slot name="header"></slot> <!-- 库名、版本信息、展开/收起按钮 -->
|
||||
</div>
|
||||
|
||||
<!-- 内容:展开/收起动画过渡 -->
|
||||
<Transition name="collapse-transition"
|
||||
@beforeEnter="beforeEnter"
|
||||
@enter="enter"
|
||||
@beforeLeave="beforeLeave"
|
||||
@leave="leave"
|
||||
>
|
||||
<div v-if="props.expand">
|
||||
<slot name="body"></slot> <!-- 漏洞表格 -->
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
```
|
||||
|
||||
**折叠动画是怎么实现的?** 手动控制 Vue Transition 的六个钩子函数:
|
||||
|
||||
```typescript
|
||||
// 展开时:先量高度(scrollHeight)→ 设置 max-height → 过渡到全高 → 清除限制
|
||||
const enter = (el) => {
|
||||
requestAnimationFrame(() => {
|
||||
el.style.maxHeight = `${el.scrollHeight}px`; // 设为元素实际高度
|
||||
});
|
||||
};
|
||||
const afterEnter = (el) => {
|
||||
el.style.maxHeight = ''; // 展开完成后清除限制,防止内容溢出
|
||||
};
|
||||
|
||||
// 收起时:先设当前高度 → 过渡回 max-height: 0
|
||||
const beforeLeave = (el) => {
|
||||
el.style.maxHeight = `${el.scrollHeight}px`; // 锁定当前高度
|
||||
};
|
||||
const leave = (el) => {
|
||||
el.style.maxHeight = 0; // 过渡回 0
|
||||
};
|
||||
```
|
||||
|
||||
**为什么不用 CSS `height: auto` 动画?** CSS 无法对 `height: auto` 做动画过渡。所以用 JS 读取 `scrollHeight` 再设置 `max-height` 的数值,这才能实现平滑的展开/收起动画。过渡曲线是 `cubic-bezier(0.5, 0.05, 0.5, 0.95)`,持续 0.3 秒。
|
||||
|
||||
### 3.4 第三步:AI 修复建议弹窗(Table.vue — 核心交互)
|
||||
|
||||
这是整个功能的核心——用户点击漏洞行里的"AI修复建议"按钮,弹出弹窗展示 AI 生成的内容:
|
||||
|
||||
```javascript
|
||||
// components/AIRepair/Table.vue(简化版核心逻辑)
|
||||
|
||||
// 1. 表格渲染每行漏洞信息 + "AI修复建议"按钮
|
||||
// <d-button @click="openModal(row)">AI修复建议</d-button>
|
||||
|
||||
// 2. 点击按钮 → 调 AI 接口获取建议
|
||||
const openModal = async (row) => {
|
||||
showModal.value = true;
|
||||
await fetchVulSuggestion(row); // 调 AI 接口
|
||||
};
|
||||
|
||||
const fetchVulSuggestion = async (row) => {
|
||||
loading.value = true;
|
||||
const { data } = await getVulSuggestion({
|
||||
name: props.libraryName, // 组件库名(如 "Log4j2")
|
||||
version: props.currentVersion, // 当前版本号(如 "2.14.0")
|
||||
cve: row.vulnId // CVE 编号(如 "CVE-2021-44228")
|
||||
});
|
||||
|
||||
if (data.code === 200) {
|
||||
vulSuggestion.value = {
|
||||
vulFeature: data.data?.vulFeature || '', // 漏洞特性
|
||||
vulDescription: data.data?.vulDescription || '', // 漏洞描述
|
||||
upgradeVersion: data.data?.upgradeVersion || '', // 建议升级版本
|
||||
fixSuggestionList: data.data?.fixSuggestionList || [] // AI修复建议列表
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// 3. 弹窗展示 AI 返回的四部分内容
|
||||
// ┌──────────────────────────────────────────┐
|
||||
// │ 漏洞特性:远程代码执行,攻击者构造恶意... │
|
||||
// │ 漏洞描述:Apache Log4j2 存在 JNDI 注入... │
|
||||
// │ 升级版本:2.17.1 │
|
||||
// │ 🤖 AI修复建议: │
|
||||
// │ • 升级至 2.17.1 或更高版本 │
|
||||
// │ • 设置 formatMsgNoLookups=true │
|
||||
// │ • 检查自定义 Lookup 插件 │
|
||||
// └──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**API 接口**:`POST /ai/vul_suggestion`,参数 `{ name, version, cve }`,返回结构化 JSON。
|
||||
|
||||
### 3.5 数据流全景
|
||||
|
||||
```
|
||||
用户进入 "AI修复建议" Tab
|
||||
│
|
||||
▼
|
||||
AIRepair/index.vue 调用
|
||||
POST /api/v1/repo/repair/info
|
||||
参数: { softwareId, current, size }
|
||||
│
|
||||
▼
|
||||
返回: { records: [{ libraryName, currentVersion,
|
||||
recommendedVersion, vulnerabilities: [...] }] }
|
||||
│
|
||||
▼
|
||||
渲染可折叠面板(Panel.vue)
|
||||
每个受影响的库 → 一个面板
|
||||
面板头部展示:库名、严重标签、问题数、升级路径
|
||||
面板内容展示:漏洞表格(Table.vue)
|
||||
│
|
||||
▼
|
||||
用户点击某行 "AI修复建议" 按钮
|
||||
│
|
||||
▼
|
||||
Table.vue 调用
|
||||
POST /ai/vul_suggestion ← 金银湖大模型
|
||||
参数: { name: "Log4j2", version: "2.14.0", cve: "CVE-2021-44228" }
|
||||
│
|
||||
▼
|
||||
返回: { vulFeature, vulDescription,
|
||||
upgradeVersion, fixSuggestionList: [...] }
|
||||
│
|
||||
▼
|
||||
弹窗展示 AI 修复建议
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、这个功能还在哪些地方用?
|
||||
|
||||
AIRepair 组件被复用在 **3 个不同的父页面**中,以 Tab 形式嵌入:
|
||||
|
||||
| 父页面 | 文件位置 | Tab 名称 |
|
||||
|--------|---------|---------|
|
||||
| **版本详情页** | `src/views/Jyh/Version/Detail/index.vue` | "AI修复建议" Tab |
|
||||
| **版本详情页(备选视图)** | `src/views/Jyh/Version/Detail/repoDetails/index2.vue` | "AI修复建议" Tab |
|
||||
| **AI Home 开源详情** | `src/views/Jyh/AI/Home/components/OssDetail/index.vue` | "AI 修复建议" Tab |
|
||||
|
||||
此外,Panel 和 Table 组件还被复用在**代码质量页**(`CodeQuality/index.vue`)中,说明这套 UI 模式在项目中有一定的通用性。
|
||||
|
||||
---
|
||||
|
||||
## 五、面试问答准备
|
||||
|
||||
### Q1:"TcodeAI助手辅助修复功能"具体做了什么?
|
||||
|
||||
> 这个功能主要是把金银湖大模型的智能分析能力集成到平台的漏洞修复流程里。用户查看某个软件版本时,平台会列出该版本依赖库中存在的已知漏洞。对于每个漏洞,用户可以点击"AI修复建议"按钮,前端会调用金银湖大模型的 `/ai/vul_suggestion` 接口,传入组件名、版本号、CVE 编号,模型会返回结构化的修复建议——包括漏洞特性、漏洞描述、建议升级版本和修复步骤列表。前端把这些内容展示在弹窗中,用户就能看到具体的修复方案。
|
||||
|
||||
### Q2:AI 接口是怎么对接的?
|
||||
|
||||
> 用的是标准的 HTTP POST 请求。前端传三个参数给后端 `/ai/vul_suggestion` 接口:`name`(库名,如 Log4j2)、`version`(当前版本号)、`cve`(CVE 编号)。后端调用金银湖大模型进行处理,返回结构化 JSON,包含 `vulFeature`(漏洞特性)、`vulDescription`(漏洞描述)、`upgradeVersion`(建议升级版本)、`fixSuggestionList`(修复建议列表)。前端直接按字段渲染就行,不需要自己解析自然语言。
|
||||
|
||||
### Q3:Panel 组件的折叠动画怎么实现的?
|
||||
|
||||
> 用 Vue 的 Transition 组件 + JavaScript 钩子函数实现的。核心思路是:因为 CSS 无法对 `height: auto` 做过渡动画,所以用 JS 在展开前读取元素的 `scrollHeight`(实际内容高度),设置 `max-height` 为目标值,让 CSS transition 驱动动画;展开完成后清掉 `max-height` 限制,防止内容溢出。收起的流程相反——先设 `max-height` 为当前高度,再过渡到 0。过渡持续 0.3 秒,使用 `cubic-bezier(0.5, 0.05, 0.5, 0.95)` 缓动曲线。
|
||||
|
||||
### Q4:这个功能是怎么嵌入到平台里的?
|
||||
|
||||
> AIRepair 组件以 Tab 的形式嵌入到三个不同的父页面中——软件版本详情页的两个视图,和 AI Home 的开源软件详情页。父页面通过 `versionId` prop 把当前查看的软件版本 ID 传给 AIRepair,AIRepair 根据这个 ID 去请求对应版本的安全漏洞信息。这种组件化的设计使得同一个功能可以在多个页面中复用,不需要重复开发。
|
||||
|
||||
### Q5:AI 返回的数据有哪些字段?怎么展示的?
|
||||
|
||||
> AI 返回四个字段:`vulFeature`(漏洞特性——描述漏洞的技术特征,如"远程代码执行,攻击者可通过构造恶意数据包触发")、`vulDescription`(漏洞描述——更详细的漏洞说明)、`upgradeVersion`(建议升级到的安全版本号)、`fixSuggestionList`(修复建议列表——一个字符串数组,每条是一条具体的修复措施)。前端用弹窗展示,前三个字段是键值对形式,修复建议用列表形式渲染。所有字段都用了 `||` 兜底为 `'--'`,防止某个字段缺失导致空白。
|
||||
|
||||
### Q6:AI 修复建议和漏洞列表是两个不同的接口,为什么要分开?
|
||||
|
||||
> 两个接口的职责不同。漏洞列表接口(`/api/v1/repo/repair/info`)返回的是批量数据——当前软件版本所有受影响依赖库的漏洞概况,数据量较大但字段较少,页面加载时一次性请求。AI 修复建议接口(`/ai/vul_suggestion`)是点对点请求——用户点击某个具体漏洞后才请求,每次只传一个 CVE 编号去查询。这种设计避免了首页加载时对每个漏洞都调一次 AI 接口,既不浪费 AI 调用额度,也保证了页面加载速度。
|
||||
|
||||
---
|
||||
|
||||
## 六、关键数字(面试时用)
|
||||
|
||||
| 数据 | 数字 |
|
||||
|------|------|
|
||||
| 组件文件数 | 3 个(index.vue + Panel.vue + Table.vue) |
|
||||
| AI API 接口数 | 2 个(`/api/v1/repo/repair/info` + `/ai/vul_suggestion`) |
|
||||
| AI 返回字段数 | 4 个(漏洞特性、漏洞描述、升级版本、修复建议列表) |
|
||||
| 嵌入父页面数 | 3+ 个(版本详情页 ×2 + AI Home详情 + 代码质量页) |
|
||||
| Panel 折叠动画过渡 | 0.3 秒,cubic-bezier 缓动 |
|
||||
|
||||
---
|
||||
|
||||
## 七、涉及的源码文件(需要看的时候查)
|
||||
|
||||
| 做什么 | 文件在哪 |
|
||||
|--------|----------|
|
||||
| AI 修复主页面 | `src/views/Jyh/AIRepair/index.vue` |
|
||||
| 可折叠面板组件 | `src/components/AIRepair/Panel.vue` |
|
||||
| 漏洞表格 + AI 建议弹窗 | `src/components/AIRepair/Table.vue` |
|
||||
| AI Home 中的修复副本 | `src/views/Jyh/AI/Home/components/OssDetail/AIRepair/index.vue` |
|
||||
| AI 修复相关 API | `src/api/jyh/index.ts`(remediationSearchRemediations、getVulSuggestion) |
|
||||
| 版本详情页(嵌入位置 1) | `src/views/Jyh/Version/Detail/index.vue` |
|
||||
| 版本详情页(嵌入位置 2) | `src/views/Jyh/Version/Detail/repoDetails/index2.vue` |
|
||||
| AI Home 详情(嵌入位置 3) | `src/views/Jyh/AI/Home/components/OssDetail/index.vue` |
|
||||
388
实习讲解/经历3-API接口前后端集成详解.md
Normal file
388
实习讲解/经历3-API接口前后端集成详解.md
Normal file
@@ -0,0 +1,388 @@
|
||||
# API 接口前后端集成 — 面试版
|
||||
|
||||
> 简历原话:**"协作设计可信态势感知平台API接口,完成50+数据接口的前后端集成"**
|
||||
>
|
||||
> 这篇文档帮你理解 API 集成层到底做了什么、怎么做的,以及面试时怎么讲。
|
||||
|
||||
---
|
||||
|
||||
## 一、先搞清楚:API 集成层是什么?
|
||||
|
||||
API 集成层是前端和后端之间的"翻译官"和"交通管制员"。它不是简单的 `axios.get('/xxx')`,而是一整套基础设施:
|
||||
|
||||
```
|
||||
页面组件(Vue 组件)
|
||||
│ 调用 API 函数
|
||||
▼
|
||||
API 函数层(29 个文件,641 个函数)
|
||||
→ 定义接口 URL、method、参数格式
|
||||
│ 调用 request()
|
||||
▼
|
||||
请求基础设施(request.ts,273 行)
|
||||
→ 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_TOKEN(Token 头)
|
||||
│ ├── 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 个文件中。
|
||||
|
||||
### Q2:Token 过期自动刷新是怎么实现的?
|
||||
|
||||
> 用了一个 `refreshing` 锁 + Promise 请求队列的机制。当请求返回 401 时,先检查 `refreshing` 是否为 true——如果是,说明已经有请求在刷新 Token 了,当前请求就包装成一个 Promise 放进等待队列;如果不是,就执行刷新并设 `refreshing = true`。刷新成功后更新 Token,然后遍历队列用新 Token 重发所有等待的请求。这样无论同时有多少个请求返回 401,都只会发一次刷新请求。
|
||||
|
||||
### Q3:为什么需要 AES 加密?
|
||||
|
||||
> 这个平台涉及安全态势数据,有一定的敏感性。后端返回的数据在传输层用 AES-128-CBC 加密,前端在响应拦截器中自动解密。加密密钥和 IV 是硬编码在前端代码中的(生产环境会用更安全的方式管理)。加密流程对业务代码完全透明——API 函数只是调用 `request()`,加密解密都在拦截器里自动完成。
|
||||
|
||||
### Q4:reqCatch 和 reqCatchV2 有什么区别?
|
||||
|
||||
> 都是 try/catch 的通用封装,避免每个页面都写 try/catch。区别在于:`reqCatch` 静默捕获错误,返回 `{ data, error }` 结构,让调用方自己判断。`reqCatchV2` 在捕获错误后还会通过事件总线 `emitEvent('responseError', e)` 通知全局——这主要用于路由守卫里,发生 403/404 时通过事件触发全局的页面跳转。新代码基本都用 V2。
|
||||
|
||||
### Q5:API 缓存降级是怎么运作的?
|
||||
|
||||
> 这是一套自研的请求降级系统。基于 IndexedDB 做持久化缓存。请求成功时自动缓存响应数据;请求失败时判断是否在熔断时间内——如果是,直接读缓存返回,用户看到的是旧数据而不是错误页面。还有最大缓存条数限制和过期清理机制。通过 `storage-apis.ts` 配置哪些接口走缓存策略,可以设置超时、重试次数、熔断时间等参数。
|
||||
|
||||
### Q6:HTTP 错误怎么统一处理的?
|
||||
|
||||
> 在响应拦截器里统一处理。根据 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,密钥 mXzfCSPBKmEA8aLq,IV 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 封装) |
|
||||
| 态势感知看板 API(50 端点) | `src/api/jyh/situation.ts` |
|
||||
| 金银湖核心 API(45 端点) | `src/api/jyh/index.ts` |
|
||||
| 金银湖首页 API(5 端点) | `src/api/jyh/home.ts` |
|
||||
| 金银湖认证 API(3 端点) | `src/api/jyh/auth.ts` |
|
||||
| 仓库管理 API(161 端点) | `src/api/repo/index.ts` |
|
||||
| 组织管理 API(55 端点) | `src/api/org/index.ts` |
|
||||
| 用户管理 API(55+ 端点) | `src/api/user/index.ts` |
|
||||
| 合并请求 API(62 端点) | `src/api/merge/index.ts` |
|
||||
| 讨论系统 API(50 端点) | `src/api/discussion/index.ts` |
|
||||
Reference in New Issue
Block a user