重试功能
自动重试失败的请求,提高应用的可靠性。
基础用法
typescript
import { Request } from '@ureq/core';
import { FetchRequestor } from '@ureq/impl-fetch';
const request = new Request(
new FetchRequestor(),
{
retry: {
maxRetries: 3, // 最多重试 3 次
retryDelay: 1000 // 每次重试间隔 1 秒
}
}
);
// 请求失败时会自动重试
const data = await request.get('/api/data');配置选项
maxRetries
最大重试次数。
typescript
{
retry: {
maxRetries: 3 // 默认值:3
}
}retryDelay
重试延迟时间(毫秒)。
typescript
{
retry: {
retryDelay: 1000 // 默认值:1000ms (1秒)
}
}shouldRetry
自定义重试条件。
typescript
import { RequestError } from '@ureq/core';
{
retry: {
shouldRetry: (error: RequestError) => {
// 只重试 5xx 错误
return error.status >= 500 && error.status < 600;
}
}
}默认重试策略
默认情况下,以下错误会触发重试:
- 网络错误 - 无法连接到服务器
- 超时错误 - 请求超时
- 5xx 错误 - 服务器内部错误
- 429 错误 - 请求过多(Rate Limit)
以下错误不会重试:
- 4xx 错误(除 429)- 客户端错误
- 自定义错误 - 业务逻辑错误
高级用法
指数退避
实现指数退避重试策略:
typescript
let retryCount = 0;
const request = new Request(
new FetchRequestor(),
{
retry: {
maxRetries: 5,
retryDelay: 1000,
shouldRetry: (error) => {
if (error.status >= 500) {
retryCount++;
// 指数退避:1s, 2s, 4s, 8s, 16s
const delay = Math.pow(2, retryCount - 1) * 1000;
return new Promise(resolve => {
setTimeout(() => resolve(true), delay);
});
}
return false;
}
}
}
);根据错误类型重试
typescript
{
retry: {
shouldRetry: (error) => {
// 网络错误:重试 3 次
if (error.message.includes('network')) {
return error.retryCount < 3;
}
// 超时错误:重试 2 次
if (error.message.includes('timeout')) {
return error.retryCount < 2;
}
// 服务器错误:重试 5 次
if (error.status >= 500) {
return error.retryCount < 5;
}
return false;
}
}
}重试回调
在重试时执行自定义逻辑:
typescript
const request = new Request(
new FetchRequestor(),
{
retry: {
maxRetries: 3,
shouldRetry: async (error) => {
console.log(`Retry attempt ${error.retryCount + 1}`);
// 记录重试日志
await logRetry({
url: error.config.url,
attempt: error.retryCount + 1,
error: error.message
});
return error.retryCount < 3;
}
}
}
);实际示例
示例 1:API 请求重试
typescript
const apiRequest = new Request(
new FetchRequestor({
baseURL: 'https://api.example.com'
}),
{
retry: {
maxRetries: 3,
retryDelay: 2000,
shouldRetry: (error) => {
// 只重试服务器错误和网络错误
return error.status >= 500 || error.message.includes('network');
}
}
}
);
try {
const data = await apiRequest.get('/users');
console.log('Success:', data);
} catch (error) {
console.error('Failed after retries:', error);
}示例 2:文件上传重试
typescript
const uploadRequest = new Request(
new FetchRequestor({
baseURL: 'https://upload.example.com'
}),
{
retry: {
maxRetries: 5,
retryDelay: 3000,
shouldRetry: (error) => {
// 上传失败时重试
if (error.status === 503 || error.status === 504) {
console.log(`Upload failed, retrying... (${error.retryCount + 1}/5)`);
return true;
}
return false;
}
},
timeout: {
timeout: 30000 // 30 秒超时
}
}
);
async function uploadFile(file: File) {
const formData = new FormData();
formData.append('file', file);
try {
const result = await uploadRequest.post('/upload', formData);
console.log('Upload successful:', result);
} catch (error) {
console.error('Upload failed after retries:', error);
}
}示例 3:带进度提示的重试
typescript
import { RequestError } from '@ureq/core';
const request = new Request(
new FetchRequestor(),
{
retry: {
maxRetries: 3,
retryDelay: 1000,
shouldRetry: (error: RequestError) => {
if (error.retryCount < 3) {
// 显示重试提示
showNotification({
type: 'warning',
message: `请求失败,正在重试... (${error.retryCount + 1}/3)`
});
return true;
}
return false;
}
}
}
);注意事项
- 幂等性 - 确保重试的请求是幂等的,避免重复操作
- 重试次数 - 不要设置过多的重试次数,避免长时间等待
- 重试延迟 - 合理设置延迟时间,避免对服务器造成压力
- 错误处理 - 即使有重试,也要处理最终失败的情况