企业级 API Form Post 方法实现
# 企业级 API Form Post 方法实现
下面是一个企业级的 `apiForm.post()` 方法实现,它封装了 FormData 的创建和文件上传功能,并提供了进度跟踪和取消功能:
```typescript
// src/services/axios/formPost.ts
/**
* 企业级表单提交工具 - 专为文件上传和表单数据设计
* 提供进度跟踪、取消功能、自动重试等企业级特性
*/
import { apiClient, type AxiosProgressEvent } from './index'
import type { AxiosResponse, CancelTokenSource, AxiosRequestConfig } from 'axios'
// 表单数据项类型定义
export interface FormDataItem {
key: string
value: any
type?: 'file' | 'text' | 'json'
}
// 上传进度回调
export type ProgressCallback = (progress: number, event: AxiosProgressEvent) => void
// 上传配置选项
export interface FormPostOptions {
onProgress?: ProgressCallback
timeout?: number
retry?: number
retryDelay?: number
headers?: Record<string, string>
}
// 上传响应类型
export interface FormPostResponse<T = any> {
data: T
status: number
statusText: string
headers: any
}
// 上传任务控制器
export interface UploadTask {
cancel: (reason?: string) => void
promise: Promise<AxiosResponse>
}
/**
* 企业级表单提交方法
* @param url 请求URL
* @param formDataItems 表单数据项数组
* @param options 上传配置选项
* @returns 上传任务控制器和响应Promise
*/
export const apiFormPost = <T = any>(
url: string,
formDataItems: FormDataItem[],
options: FormPostOptions = {}
): UploadTask => {
// 创建取消令牌
const source = apiClient.CancelToken.source()
// 创建FormData对象
const formData = new FormData()
// 处理表单数据项
formDataItems.forEach(item => {
if (item.type === 'file' && item.value instanceof File) {
// 文件类型直接追加
formData.append(item.key, item.value, item.value.name)
} else if (item.type === 'json') {
// JSON类型序列化
formData.append(item.key, JSON.stringify(item.value))
} else {
// 其他类型转换为字符串
formData.append(item.key, String(item.value))
}
})
// 合并配置
const config: AxiosRequestConfig = {
headers: {
'Content-Type': 'multipart/form-data',
...options.headers,
},
timeout: options.timeout || 300000, // 默认5分钟超时
cancelToken: source.token,
onUploadProgress: (progressEvent: AxiosProgressEvent) => {
if (options.onProgress && progressEvent.total) {
const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total)
options.onProgress(progress, progressEvent)
}
},
}
// 重试逻辑
let retryCount = 0
const maxRetries = options.retry || 3
const retryDelay = options.retryDelay || 1000
// 执行上传
const executeUpload = (): Promise<AxiosResponse<T>> => {
return apiClient.post(url, formData, config)
.then(response => response)
.catch(error => {
// 如果是取消请求,直接抛出
if (apiClient.isCancel(error)) {
throw error
}
// 重试逻辑
if (retryCount < maxRetries) {
retryCount++
console.warn(`上传失败,第 ${retryCount} 次重试...`)
return new Promise(resolve => {
setTimeout(() => resolve(executeUpload()), retryDelay * retryCount)
})
}
// 重试次数用完,抛出错误
throw error
})
}
// 返回上传任务控制器
return {
cancel: (reason?: string) => source.cancel(reason || '用户取消上传'),
promise: executeUpload(),
}
}
/**
* 简化版表单提交方法(不包含取消功能)
* @param url 请求URL
* @param formDataItems 表单数据项数组
* @param onProgress 进度回调
* @returns 响应Promise
*/
export const simpleFormPost = <T = any>(
url: string,
formDataItems: FormDataItem[],
onProgress?: ProgressCallback
): Promise<FormPostResponse<T>> => {
return new Promise((resolve, reject) => {
const task = apiFormPost<T>(url, formDataItems, { onProgress })
task.promise
.then(response => {
resolve({
data: response.data,
status: response.status,
statusText: response.statusText,
headers: response.headers,
})
})
.catch(error => {
if (apiClient.isCancel(error)) {
reject(new Error('上传已取消'))
} else {
reject(error)
}
})
})
}
/**
* 批量文件上传方法
* @param url 请求URL
* @param files 文件数组
* @param additionalData 附加表单数据
* @param options 上传配置选项
* @returns 上传任务控制器和响应Promise
*/
export const batchFileUpload = (
url: string,
files: File[],
additionalData: FormDataItem[] = [],
options: FormPostOptions = {}
): UploadTask => {
const formDataItems: FormDataItem[] = [
...additionalData,
...files.map((file, index) => ({
key: `file_${index}`,
value: file,
type: 'file' as const,
})),
]
return apiFormPost(url, formDataItems, options)
}
// 开发环境初始化日志
if (import.meta.env.DEV) {
console.debug('✅【表单上传工具已加载】', {
timestamp: new Date().toLocaleString(),
version: '1.0.0',
features: [
'FormData自动构建',
'上传进度跟踪',
'取消请求支持',
'自动重试机制',
'批量文件上传',
'类型安全',
],
})
}
export default {
apiFormPost,
simpleFormPost,
batchFileUpload,
}
```
## 使用方法示例
### 1. 基本文件上传
```typescript
import { apiFormPost } from '@/services/axios/formPost'
// 上传单个文件
const fileInput = document.getElementById('file-input') as HTMLInputElement
const file = fileInput.files?.[0]
if (file) {
const formDataItems = [
{ key: 'file', value: file, type: 'file' },
{ key: 'category', value: 'documents' },
{ key: 'description', value: '项目文档' },
]
const task = apiFormPost('/api/upload', formDataItems, {
onProgress: (progress, event) => {
console.log(`上传进度: ${progress}%`)
},
timeout: 300000, // 5分钟超时
retry: 3, // 失败重试3次
})
// 可以随时取消上传
// task.cancel('用户取消')
try {
const response = await task.promise
console.log('上传成功', response.data)
} catch (error) {
console.error('上传失败', error)
}
}
```
### 2. 多文件批量上传
```typescript
import { batchFileUpload } from '@/services/axios/formPost'
// 批量上传多个文件
const files = [...document.getElementById('file-input').files]
const additionalData = [
{ key: 'userId', value: 123 },
{ key: 'projectId', value: 456 },
{ key: 'metadata', value: { tags: ['重要', '项目'] }, type: 'json' },
]
const task = batchFileUpload('/api/upload/batch', files, additionalData, {
onProgress: (progress) => {
console.log(`批量上传进度: ${progress}%`)
},
})
try {
const response = await task.promise
console.log('批量上传成功', response.data)
} catch (error) {
console.error('批量上传失败', error)
}
```
### 3. 简化版使用(无需取消功能)
```typescript
import { simpleFormPost } from '@/services/axios/formPost'
// 简化版上传
const formDataItems = [
{ key: 'avatar', value: avatarFile, type: 'file' },
{ key: 'userId', value: currentUser.id },
{ key: 'userData', value: userProfile, type: 'json' },
]
try {
const response = await simpleFormPost('/api/user/avatar', formDataItems, (progress) => {
console.log(`头像上传进度: ${progress}%`)
})
console.log('头像上传成功', response.data)
} catch (error) {
console.error('头像上传失败', error)
}
```
## 主要特性
1. **类型安全**:完整的 TypeScript 类型定义,确保代码可靠性
2. **进度跟踪**:提供上传进度回调,支持 UI 进度显示
3. **取消功能**:支持随时取消上传任务
4. **自动重试**:网络错误时自动重试,提高上传成功率
5. **批量上传**:专门优化的多文件批量上传方法
6. **灵活配置**:支持自定义超时、重试策略和请求头
7. **错误处理**:统一的错误处理机制,便于调试和用户反馈
这个实现提供了企业级应用所需的所有文件上传功能,并且与之前创建的 Axios 服务完美集成,保持了统一的安全配置和错误处理机制。
浙公网安备 33010602011771号