965
docs/11-API接口设计规范.md
Normal file
965
docs/11-API接口设计规范.md
Normal file
@@ -0,0 +1,965 @@
|
||||
# 模块11:API接口设计规范
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI设计系统概览
|
||||
|
||||
> **完整设计系统文档请参考:** `UI设计系统.md`
|
||||
|
||||
### 核心设计原则
|
||||
- **现代简约**:界面清晰,层次分明
|
||||
- **专业高效**:减少操作步骤,提升工作效率
|
||||
- **一致性**:统一的视觉语言和交互模式
|
||||
- **可访问性**:符合WCAG 2.1 AA标准
|
||||
|
||||
### 关键设计令牌
|
||||
|
||||
**颜色系统:**
|
||||
- 主色:`#0d6efd`(操作按钮、选中状态)
|
||||
- 成功:`#198754`(连接成功状态)
|
||||
- 危险:`#dc3545`(删除操作、错误提示)
|
||||
- 深灰:`#212529`(导航栏背景)
|
||||
- 浅灰:`#e9ecef`(工具栏背景)
|
||||
|
||||
**字体系统:**
|
||||
- 字体族:系统字体栈(-apple-system, Segoe UI, Roboto等)
|
||||
- 正文:14px,行高1.5
|
||||
- 标题:20-32px,行高1.2-1.4
|
||||
- 小号文字:12px(文件大小、日期等)
|
||||
|
||||
**间距系统:**
|
||||
- 基础单位:8px
|
||||
- 标准间距:16px(1rem)
|
||||
- 组件内边距:8px-16px
|
||||
|
||||
**组件规范:**
|
||||
- 导航栏:高度48px,深色背景
|
||||
- 工具栏:浅灰背景,按钮间距8px
|
||||
- 文件项:最小高度44px,悬停效果150ms
|
||||
- 按钮:圆角4px,过渡150ms
|
||||
|
||||
**交互规范:**
|
||||
- 悬停效果:150ms过渡
|
||||
- 触摸目标:最小44x44px
|
||||
- 键盘导航:Tab、Enter、Delete、F2、F5、Esc
|
||||
- 焦点状态:2px蓝色轮廓
|
||||
|
||||
**响应式断点:**
|
||||
- 移动端:< 768px(双面板垂直排列)
|
||||
- 平板:768px - 1024px
|
||||
- 桌面:> 1024px(标准布局)
|
||||
|
||||
---
|
||||
|
||||
## 11.1 RESTful设计原则
|
||||
|
||||
### 11.1.1 URL设计规范
|
||||
|
||||
**设计原则:**
|
||||
1. 使用名词复数形式(/api/files)
|
||||
2. 使用HTTP方法表示操作类型
|
||||
3. 使用查询参数传递可选参数
|
||||
4. 使用路径参数传递必需参数
|
||||
|
||||
**命名规范:**
|
||||
- URL使用小写字母
|
||||
- 单词之间使用连字符(-)分隔
|
||||
- 资源名称使用复数形式
|
||||
- 层级关系使用斜杠(/)分隔
|
||||
|
||||
**示例:**
|
||||
```
|
||||
✅ 正确:
|
||||
GET /api/files/list
|
||||
POST /api/files/upload
|
||||
DELETE /api/files/{id}
|
||||
|
||||
❌ 错误:
|
||||
GET /api/getFiles
|
||||
POST /api/files/create
|
||||
DELETE /api/deleteFile/123
|
||||
```
|
||||
|
||||
### 11.1.2 HTTP方法映射
|
||||
|
||||
| 方法 | 操作 | 是否幂等 | 说明 | 示例 |
|
||||
|------|------|---------|------|------|
|
||||
| GET | 查询 | 是 | 获取资源列表或详情 | GET /api/files/list |
|
||||
| POST | 创建 | 否 | 创建新资源 | POST /api/files/mkdir |
|
||||
| PUT | 更新 | 是 | 完整更新资源 | PUT /api/files/rename |
|
||||
| DELETE | 删除 | 是 | 删除资源 | DELETE /api/files/delete |
|
||||
|
||||
### 11.1.3 统一响应格式
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "操作成功",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "操作失败",
|
||||
"error": "错误详细信息"
|
||||
}
|
||||
```
|
||||
|
||||
**列表响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": [
|
||||
{},
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"total": 100
|
||||
}
|
||||
```
|
||||
|
||||
**分页响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": [],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"pageSize": 20,
|
||||
"total": 100,
|
||||
"totalPages": 5
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11.2 完整API列表
|
||||
|
||||
### 11.2.1 连接管理API
|
||||
|
||||
#### 建立SFTP连接
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/connection/connect
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"name": "测试服务器",
|
||||
"host": "192.168.1.100",
|
||||
"port": 22,
|
||||
"username": "root",
|
||||
"password": "123456",
|
||||
"privateKeyPath": "/path/to/private/key",
|
||||
"passPhrase": "key_password",
|
||||
"rootPath": "/home/user"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "连接成功",
|
||||
"data": {
|
||||
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "连接失败",
|
||||
"error": "认证失败:用户名或密码错误"
|
||||
}
|
||||
```
|
||||
|
||||
#### 断开连接
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/connection/disconnect
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "断开成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 保存连接配置
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/connection/save
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "测试服务器",
|
||||
"host": "192.168.1.100",
|
||||
"port": 22,
|
||||
"username": "root",
|
||||
"password": "encrypted_password",
|
||||
"privateKeyPath": "/path/to/private/key",
|
||||
"passPhrase": "encrypted_key_password",
|
||||
"rootPath": "/home/user",
|
||||
"connectTimeout": 10000
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "保存成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "测试服务器",
|
||||
"host": "192.168.1.100",
|
||||
"port": 22,
|
||||
"username": "root",
|
||||
"createdAt": "2024-02-02T10:00:00",
|
||||
"updatedAt": "2024-02-02T10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取所有保存的连接
|
||||
|
||||
**请求:**
|
||||
```
|
||||
GET /api/connection/list
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "测试服务器",
|
||||
"host": "192.168.1.100",
|
||||
"port": 22,
|
||||
"username": "root",
|
||||
"createdAt": "2024-02-02T10:00:00",
|
||||
"updatedAt": "2024-02-02T10:00:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取指定连接
|
||||
|
||||
**请求:**
|
||||
```
|
||||
GET /api/connection/{id}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"id": 1,
|
||||
"name": "测试服务器",
|
||||
"host": "192.168.1.100",
|
||||
"port": 22,
|
||||
"username": "root",
|
||||
"createdAt": "2024-02-02T10:00:00",
|
||||
"updatedAt": "2024-02-02T10:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应(连接不存在):**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "连接不存在",
|
||||
"error": "ID为1的连接不存在"
|
||||
}
|
||||
```
|
||||
|
||||
#### 删除连接配置
|
||||
|
||||
**请求:**
|
||||
```
|
||||
DELETE /api/connection/{id}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "删除成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取活跃连接列表
|
||||
|
||||
**请求:**
|
||||
```
|
||||
GET /api/connection/active
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"sftp-12345678-1234-1234-1234-123456789abc": {
|
||||
"id": 1,
|
||||
"name": "测试服务器",
|
||||
"host": "192.168.1.100",
|
||||
"port": 22,
|
||||
"username": "root"
|
||||
},
|
||||
"sftp-87654321-4321-4321-4321-cba987654321": {
|
||||
"id": 2,
|
||||
"name": "生产服务器",
|
||||
"host": "192.168.1.200",
|
||||
"port": 22,
|
||||
"username": "admin"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 11.2.2 文件操作API
|
||||
|
||||
#### 列出文件
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/list
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
|
||||
"path": "/home/user"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": [
|
||||
{
|
||||
"name": "Documents",
|
||||
"path": "/home/user/Documents",
|
||||
"size": 0,
|
||||
"isDirectory": true,
|
||||
"modifiedTime": "2024-02-02T10:00:00",
|
||||
"permissions": "drwxr-xr-x"
|
||||
},
|
||||
{
|
||||
"name": "test.txt",
|
||||
"path": "/home/user/test.txt",
|
||||
"size": 1024,
|
||||
"isDirectory": false,
|
||||
"modifiedTime": "2024-02-02T10:00:00",
|
||||
"permissions": "-rw-r--r--"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取文件信息
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/info
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
|
||||
"path": "/home/user/test.txt"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"name": "test.txt",
|
||||
"path": "/home/user/test.txt",
|
||||
"size": 1024,
|
||||
"isDirectory": false,
|
||||
"modifiedTime": "2024-02-02T10:00:00",
|
||||
"permissions": "-rw-r--r--"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 获取当前路径
|
||||
|
||||
**请求:**
|
||||
```
|
||||
GET /api/files/path?sessionId=sftp-12345678-1234-1234-1234-123456789abc
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "查询成功",
|
||||
"data": {
|
||||
"path": "/home/user"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 上传文件
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/upload
|
||||
Content-Type: multipart/form-data
|
||||
|
||||
file: [文件内容]
|
||||
targetSessionId: sftp-12345678-1234-1234-1234-123456789abc
|
||||
targetPath: /home/user/
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "上传成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
**错误响应:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "上传失败",
|
||||
"error": "目标目录不存在"
|
||||
}
|
||||
```
|
||||
|
||||
#### 下载文件
|
||||
|
||||
**请求:**
|
||||
```
|
||||
GET /api/files/download?sessionId=sftp-12345678-1234-1234-1234-123456789abc&path=/home/user/test.txt
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```
|
||||
[文件流]
|
||||
```
|
||||
|
||||
**响应头:**
|
||||
```
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment; filename=test.txt
|
||||
Content-Length: 1024
|
||||
```
|
||||
|
||||
#### 服务器间传输
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/transfer
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sourceSessionId": "sftp-12345678-1234-1234-1234-123456789abc",
|
||||
"sourcePath": "/home/user/test.txt",
|
||||
"targetSessionId": "sftp-87654321-4321-4321-4321-cba987654321",
|
||||
"targetPath": "/home/target/"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "传输成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 删除文件
|
||||
|
||||
**请求:**
|
||||
```
|
||||
DELETE /api/files/delete?sessionId=sftp-12345678-1234-1234-1234-123456789abc&path=/home/user/test.txt
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "删除成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 批量删除
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/batch-delete
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sessionId": "local",
|
||||
"paths": [
|
||||
"C:/test/file1.txt",
|
||||
"C:/test/file2.txt",
|
||||
"C:/test/file3.txt"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "删除完成",
|
||||
"data": {
|
||||
"successCount": 2,
|
||||
"failCount": 1,
|
||||
"failedFiles": [
|
||||
"C:/test/file3.txt - 没有删除权限"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 重命名
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/rename
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sessionId": "sftp-12345678-1234-1234-1234-123456789abc",
|
||||
"oldPath": "/home/user/old.txt",
|
||||
"newPath": "/home/user/new.txt"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "重命名成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
#### 新建文件夹
|
||||
|
||||
**请求:**
|
||||
```
|
||||
POST /api/files/mkdir
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"sessionId": "local",
|
||||
"path": "C:/test/newfolder"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "创建成功",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
## 11.3 错误码定义
|
||||
|
||||
### 11.3.1 HTTP状态码
|
||||
|
||||
| 状态码 | 说明 | 使用场景 |
|
||||
|--------|------|---------|
|
||||
| 200 | OK | 请求成功 |
|
||||
| 201 | Created | 资源创建成功 |
|
||||
| 400 | Bad Request | 请求参数错误 |
|
||||
| 401 | Unauthorized | 未授权(连接失败) |
|
||||
| 403 | Forbidden | 权限不足 |
|
||||
| 404 | Not Found | 资源不存在 |
|
||||
| 500 | Internal Server Error | 服务器内部错误 |
|
||||
|
||||
### 11.3.2 业务错误码
|
||||
|
||||
```java
|
||||
public enum ErrorCode {
|
||||
SUCCESS(0, "成功"),
|
||||
INVALID_PARAMETER(1001, "参数错误"),
|
||||
CONNECTION_NOT_FOUND(2001, "连接不存在"),
|
||||
CONNECTION_FAILED(2002, "连接失败"),
|
||||
FILE_NOT_FOUND(3001, "文件不存在"),
|
||||
FILE_ALREADY_EXISTS(3002, "文件已存在"),
|
||||
INSUFFICIENT_PERMISSION(3003, "权限不足"),
|
||||
DISK_SPACE_FULL(3004, "磁盘空间不足"),
|
||||
OPERATION_FAILED(5000, "操作失败");
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
ErrorCode(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 11.3.3 错误响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "操作失败",
|
||||
"error": {
|
||||
"code": 3001,
|
||||
"message": "文件不存在",
|
||||
"details": "文件 /home/user/test.txt 不存在"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11.4 API版本管理
|
||||
|
||||
### 11.4.1 URL版本控制
|
||||
|
||||
```
|
||||
/api/v1/connection/connect
|
||||
/api/v2/connection/connect
|
||||
```
|
||||
|
||||
### 11.4.2 请求头版本控制
|
||||
|
||||
```
|
||||
GET /api/connection/list
|
||||
Accept: application/vnd.sftp-manager.v1+json
|
||||
```
|
||||
|
||||
### 11.4.3 查询参数版本控制
|
||||
|
||||
```
|
||||
GET /api/connection/list?version=1
|
||||
```
|
||||
|
||||
## 11.5 API文档生成
|
||||
|
||||
### 11.5.1 Swagger集成
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-ui</artifactId>
|
||||
<version>1.6.14</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 11.5.2 Swagger配置
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI springShopOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info().title("SFTP文件管理系统API")
|
||||
.description("SFTP文件管理系统REST API文档")
|
||||
.version("v1.0.0"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 11.5.3 注解示例
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/connection")
|
||||
@Tag(name = "连接管理", description = "SFTP连接相关接口")
|
||||
public class ConnectionController {
|
||||
|
||||
@Operation(summary = "建立SFTP连接", description = "根据连接参数建立SFTP连接")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "连接成功"),
|
||||
@ApiResponse(responseCode = "400", description = "参数错误"),
|
||||
@ApiResponse(responseCode = "500", description = "连接失败")
|
||||
})
|
||||
@PostMapping("/connect")
|
||||
public ApiResponse<String> connect(
|
||||
@Parameter(description = "连接参数", required = true)
|
||||
@RequestBody ConnectionRequest request) {
|
||||
// 实现
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 11.6 API测试
|
||||
|
||||
### 11.6.1 Postman测试
|
||||
|
||||
导入以下JSON到Postman:
|
||||
|
||||
```json
|
||||
{
|
||||
"info": {
|
||||
"name": "SFTP Manager API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "连接管理",
|
||||
"item": [
|
||||
{
|
||||
"name": "建立SFTP连接",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/connection/connect",
|
||||
"host": ["{{baseUrl}}"],
|
||||
"path": ["api", "connection", "connect"]
|
||||
},
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"测试服务器\",\n \"host\": \"192.168.1.100\",\n \"port\": 22,\n \"username\": \"root\",\n \"password\": \"123456\"\n}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 11.6.2 curl测试
|
||||
|
||||
```bash
|
||||
# 测试连接API
|
||||
curl -X POST http://localhost:8080/sftp-manager/api/connection/connect \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"测试","host":"192.168.1.100","port":22,"username":"root","password":"123456"}'
|
||||
|
||||
# 测试文件列表API
|
||||
curl -X POST http://localhost:8080/sftp-manager/api/files/list \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"sessionId":"local","path":"C:/Users"}'
|
||||
```
|
||||
|
||||
## 11.7 安全规范
|
||||
|
||||
### 11.7.1 认证与会话
|
||||
|
||||
- **Session 管理**:连接建立后服务端维护 `sessionId`,前端在后续请求中携带
|
||||
- **敏感字段**:密码、密钥口令等不入库明文,保存连接配置时使用加密存储
|
||||
- **请求头**:可在 Header 中传递 `X-Session-Id` 作为会话标识(与 body 中的 sessionId 二选一或并存校验)
|
||||
|
||||
### 11.7.2 CORS 配置
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/api/**")
|
||||
.allowedOriginPatterns("http://localhost:*", "https://your-domain.com")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true)
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 11.7.3 敏感数据脱敏
|
||||
|
||||
- 列表/详情接口返回连接信息时,不返回 `password`、`passPhrase`
|
||||
- 日志中禁止打印密码、密钥内容;错误信息可返回“认证失败”等笼统描述
|
||||
|
||||
---
|
||||
|
||||
## 11.8 限流与性能建议
|
||||
|
||||
### 11.8.1 建议限流策略
|
||||
|
||||
| 接口类型 | 建议限流 |
|
||||
|----------------|-----------------------------|
|
||||
| 连接/断开 | 每 IP 每分钟 10 次 |
|
||||
| 文件列表/信息 | 每 session 每秒 20 次 |
|
||||
| 上传/下载 | 按连接数 + 单文件大小限制 |
|
||||
| 删除/重命名 | 每 session 每秒 10 次 |
|
||||
|
||||
### 11.8.2 大文件与流式传输
|
||||
|
||||
- **上传**:使用 `multipart/form-data`,服务端流式写入,避免整文件进内存
|
||||
- **下载**:使用 `InputStreamResource` 或 `StreamingResponseBody` 流式输出
|
||||
- **服务器间传输**:服务端到服务端流式转发,不落本地盘(或使用临时缓冲区流式处理)
|
||||
|
||||
---
|
||||
|
||||
## 11.9 前端调用示例(Vue 3 + Axios)
|
||||
|
||||
### 11.9.1 封装 baseURL 与响应处理
|
||||
|
||||
```typescript
|
||||
// api/client.ts
|
||||
import axios, { type AxiosInstance } from 'axios';
|
||||
|
||||
const api: AxiosInstance = axios.create({
|
||||
baseURL: '/sftp-manager/api',
|
||||
timeout: 30000,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
api.interceptors.response.use(
|
||||
(res) => {
|
||||
const { success, data, message } = res.data ?? {};
|
||||
if (!success) return Promise.reject(new Error(message || '请求失败'));
|
||||
return res.data;
|
||||
},
|
||||
(err) => Promise.reject(err.response?.data?.message || err.message)
|
||||
);
|
||||
|
||||
export default api;
|
||||
```
|
||||
|
||||
### 11.9.2 连接管理示例
|
||||
|
||||
```typescript
|
||||
// api/connection.ts
|
||||
import api from './client';
|
||||
|
||||
export interface ConnectParams {
|
||||
name: string;
|
||||
host: string;
|
||||
port: number;
|
||||
username: string;
|
||||
password?: string;
|
||||
privateKeyPath?: string;
|
||||
passPhrase?: string;
|
||||
rootPath?: string;
|
||||
}
|
||||
|
||||
export function connect(params: ConnectParams) {
|
||||
return api.post<{ data: { sessionId: string } }>('/connection/connect', params);
|
||||
}
|
||||
|
||||
export function disconnect(sessionId: string) {
|
||||
return api.post('/connection/disconnect', { sessionId });
|
||||
}
|
||||
|
||||
export function getConnectionList() {
|
||||
return api.get<{ data: Array<{ id: number; name: string; host: string; port: number; username: string }> }>('/connection/list');
|
||||
}
|
||||
```
|
||||
|
||||
### 11.9.3 文件操作示例
|
||||
|
||||
```typescript
|
||||
// api/files.ts
|
||||
import api from './client';
|
||||
|
||||
export interface FileItem {
|
||||
name: string;
|
||||
path: string;
|
||||
size: number;
|
||||
isDirectory: boolean;
|
||||
modifiedTime: string;
|
||||
permissions?: string;
|
||||
}
|
||||
|
||||
export function listFiles(sessionId: string, path: string) {
|
||||
return api.post<{ data: Array<FileItem> }>('/files/list', { sessionId, path });
|
||||
}
|
||||
|
||||
export function uploadFile(sessionId: string, targetPath: string, file: File) {
|
||||
const form = new FormData();
|
||||
form.append('file', file);
|
||||
form.append('targetSessionId', sessionId);
|
||||
form.append('targetPath', targetPath);
|
||||
return api.post('/files/upload', form, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadFile(sessionId: string, path: string) {
|
||||
return api.get('/files/download', {
|
||||
params: { sessionId, path },
|
||||
responseType: 'blob',
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteFile(sessionId: string, path: string) {
|
||||
return api.delete('/files/delete', { params: { sessionId, path } });
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11.10 健康检查与就绪探针(可选)
|
||||
|
||||
便于容器化部署与负载均衡探测:
|
||||
|
||||
| 路径 | 方法 | 说明 |
|
||||
|-------------------|------|----------------|
|
||||
| `/actuator/health` | GET | 应用存活检查 |
|
||||
| `/actuator/ready` | GET | 就绪(依赖就绪)|
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **统一响应格式**:所有API使用统一的响应格式
|
||||
2. **错误处理**:提供详细的错误信息
|
||||
3. **参数验证**:严格验证请求参数
|
||||
4. **安全性**:敏感数据加密传输
|
||||
5. **性能**:大文件使用流式传输
|
||||
|
||||
## 下一步
|
||||
|
||||
完成模块11后,继续模块12:错误处理与日志
|
||||
Reference in New Issue
Block a user