|
| 1 | +# HTTP 请求模块使用指南 |
| 2 | + |
| 3 | +位置: `src/service/http.js` |
| 4 | + |
| 5 | +基于原生 `fetch` API 封装的 HTTP 客户端,提供了统一的错误处理、拦截器、超时控制、文件处理等功能,并包含一套 React Hooks。 |
| 6 | + |
| 7 | +## 引入方式 |
| 8 | + |
| 9 | +推荐使用命名导入,以便同时使用 Hooks: |
| 10 | + |
| 11 | +```javascript |
| 12 | +import { http, useGet, usePost } from '@/service/http' |
| 13 | +``` |
| 14 | + |
| 15 | +也可以使用默认导入(仅使用 http 实例时): |
| 16 | + |
| 17 | +```javascript |
| 18 | +import http from '@/service/http' |
| 19 | +``` |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## 一、HTTP 客户端 (HttpClient) |
| 24 | + |
| 25 | +`http` 是 `HttpClient` 的实例,提供了类似 Axios 的 API。 |
| 26 | + |
| 27 | +### 1. 基础请求方法 |
| 28 | + |
| 29 | +```javascript |
| 30 | +// GET 请求 (参数自动序列化) |
| 31 | +const res = await http.get('/api/users', { page: 1, type: 'active' }) |
| 32 | + |
| 33 | +// POST 请求 |
| 34 | +const res = await http.post('/api/users', { name: 'John', age: 30 }) |
| 35 | + |
| 36 | +// PUT / PATCH / DELETE |
| 37 | +await http.put('/api/users/1', { name: 'John Doe' }) |
| 38 | +await http.patch('/api/users/1', { status: 'inactive' }) |
| 39 | +await http.delete('/api/users/1') |
| 40 | +``` |
| 41 | + |
| 42 | +### 2. 文件上传与下载 |
| 43 | + |
| 44 | +**文件上传** (自动处理 `Content-Type`): |
| 45 | + |
| 46 | +```javascript |
| 47 | +const formData = new FormData() |
| 48 | +formData.append('file', file) |
| 49 | +await http.upload('/api/upload', formData) |
| 50 | +``` |
| 51 | + |
| 52 | +**文件下载** (支持进度回调): |
| 53 | + |
| 54 | +```javascript |
| 55 | +await http.download('/api/export', { id: 123 }, 'report.xlsx', { |
| 56 | + onProgress: ({ percent, loaded, total }) => { |
| 57 | + console.log(`下载进度: ${percent}%`) |
| 58 | + } |
| 59 | +}) |
| 60 | +``` |
| 61 | + |
| 62 | +### 3. 高级功能 |
| 63 | + |
| 64 | +**拦截器**: |
| 65 | + |
| 66 | +```javascript |
| 67 | +// 请求拦截器 |
| 68 | +http.useRequestInterceptor(config => { |
| 69 | + config.headers['Authorization'] = 'Bearer token' |
| 70 | + return config |
| 71 | +}) |
| 72 | + |
| 73 | +// 响应拦截器 |
| 74 | +http.useResponseInterceptor((data, config) => { |
| 75 | + return data.result // 提取核心数据 |
| 76 | +}) |
| 77 | +``` |
| 78 | + |
| 79 | +**重试机制**: |
| 80 | + |
| 81 | +```javascript |
| 82 | +// 失败自动重试 3 次,间隔 1 秒 |
| 83 | +await http.retry(() => http.get('/api/unstable'), 3, 1000) |
| 84 | +``` |
| 85 | + |
| 86 | +**并发请求**: |
| 87 | + |
| 88 | +```javascript |
| 89 | +const [user, posts] = await http.parallel([ |
| 90 | + { url: '/api/user/1' }, |
| 91 | + { url: '/api/user/1/posts' } |
| 92 | +]) |
| 93 | +``` |
| 94 | + |
| 95 | +**取消请求**: |
| 96 | + |
| 97 | +```javascript |
| 98 | +const controller = new AbortController() |
| 99 | +http.get('/api/long-task', {}, { controller }) |
| 100 | +controller.abort() // 取消请求 |
| 101 | +``` |
| 102 | + |
| 103 | +**禁用时间戳后缀**: |
| 104 | + |
| 105 | +默认情况下,`GET` 和 `DELETE` 请求会自动添加时间戳参数 `_` 以防止缓存。如果不需要此行为,可手动禁用。 |
| 106 | + |
| 107 | +```javascript |
| 108 | +await http.get('/api/static-data', {}, { |
| 109 | + addTimestamp: false // 禁用自动添加时间戳 |
| 110 | +}) |
| 111 | +``` |
| 112 | + |
| 113 | +--- |
| 114 | + |
| 115 | +## 二、React Hooks |
| 116 | + |
| 117 | +提供了一组 Hooks 用于在组件中便捷地发起请求,自动管理 `loading` 和 `error` 状态,并在组件卸载时自动取消请求。 |
| 118 | + |
| 119 | +### 1. useRequest (基础 Hook) |
| 120 | + |
| 121 | +```javascript |
| 122 | +const [data, loading, error, refetch] = useRequest('/api/data', { |
| 123 | + method: 'GET', |
| 124 | + params: { id: 1 } |
| 125 | +}) |
| 126 | +``` |
| 127 | + |
| 128 | +### 2. 快捷 Hooks |
| 129 | + |
| 130 | +* `useGet(url, options)` - GET 请求 |
| 131 | +* `usePost(url, options)` - POST 请求 |
| 132 | +* `usePut(url, options)` - PUT 请求 |
| 133 | +* `useDelete(url, options)` - DELETE 请求 |
| 134 | +* `usePatch(url, options)` - PATCH 请求 |
| 135 | + |
| 136 | +**示例**: |
| 137 | + |
| 138 | +```javascript |
| 139 | +const UserProfile = ({ id }) => { |
| 140 | + const [user, loading, error, refresh] = useGet('/api/user', { id }) |
| 141 | + |
| 142 | + if (loading) return <Spin /> |
| 143 | + if (error) return <Alert message={error.message} /> |
| 144 | + |
| 145 | + return ( |
| 146 | + <div> |
| 147 | + <h1>{user.name}</h1> |
| 148 | + <Button onClick={() => refresh()}>刷新</Button> |
| 149 | + </div> |
| 150 | + ) |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +--- |
| 155 | + |
| 156 | +## 三、默认行为说明 |
| 157 | + |
| 158 | +1. **Suffix 处理**: 默认拦截器会自动为 `GET` 和 `DELETE` 请求的参数添加时间戳后缀(参数名为 `_`),以防止浏览器缓存。可通过配置 `addTimestamp: false` 禁用。 |
| 159 | +2. **错误处理**: 默认情况下,请求失败会自动弹出全局错误提示 (`showMessage.error`)。可通过配置 `isShowError: false` 关闭。 |
| 160 | +3. **业务状态码**: 响应拦截器会自动检查 `data.code`。如果非 0 或 200,将抛出错误;如果是 41002,将跳转至登录页。 |
| 161 | + |
| 162 | +--- |
| 163 | + |
| 164 | +## 四、API 参考 |
| 165 | + |
| 166 | +### FetchClient 配置 (Config) |
| 167 | +| 属性 | 类型 | 默认值 | 说明 | |
| 168 | +|---|---|---|---| |
| 169 | +| `BASE_URL` | string | `process.env.APP_BASE_URL` | 基础 URL | |
| 170 | +| `TIMEOUT` | number | `20000` | 超时时间 (ms) | |
| 171 | +| `HEADERS` | object | `{'Content-Type': 'application/json'}` | 默认请求头 | |
| 172 | +| `isShowError` | boolean | `true` | 请求失败时是否自动弹出错误提示 | |
| 173 | +| `addTimestamp` | boolean | `true` | 是否为 GET/DELETE 请求自动添加时间戳后缀 | |
| 174 | + |
| 175 | +### http 实例方法 |
| 176 | +- `request(url, options)` |
| 177 | +- `get(url, params, config)` |
| 178 | +- `post(url, payload, config)` |
| 179 | +- `put(url, payload, config)` |
| 180 | +- `delete(url, params, config)` |
| 181 | +- `patch(url, payload, config)` |
| 182 | +- `upload(url, formData, config)` |
| 183 | +- `download(url, params, fileName, config)` |
| 184 | +- `retry(fn, retries, delay)` |
| 185 | +- `parallel(tasks)` |
0 commit comments