精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

JavaScript原生實戰(zhàn)手冊 · 異步重試機(jī)制:網(wǎng)絡(luò)請求的可靠性保障

開發(fā) 前端
在現(xiàn)代Web應(yīng)用中,網(wǎng)絡(luò)請求無處不在:調(diào)用API獲取數(shù)據(jù)、上傳文件、發(fā)送表單、實時通信等。但網(wǎng)絡(luò)環(huán)境往往不可預(yù)測:服務(wù)器臨時過載、網(wǎng)絡(luò)連接不穩(wěn)定、CDN節(jié)點故障、第三方服務(wù)限流等問題時有發(fā)生。

在現(xiàn)代Web應(yīng)用中,網(wǎng)絡(luò)請求無處不在:調(diào)用API獲取數(shù)據(jù)、上傳文件、發(fā)送表單、實時通信等。但網(wǎng)絡(luò)環(huán)境往往不可預(yù)測:服務(wù)器臨時過載、網(wǎng)絡(luò)連接不穩(wěn)定、CDN節(jié)點故障、第三方服務(wù)限流等問題時有發(fā)生。一個偶然的網(wǎng)絡(luò)錯誤就可能讓整個功能失效,影響用戶體驗。今天我們就來打造一個智能的異步重試機(jī)制,讓應(yīng)用在各種不穩(wěn)定環(huán)境中都能穩(wěn)定運行。

生活中的重試機(jī)制場景

場景一:在線支付系統(tǒng)

想象你在開發(fā)一個電商網(wǎng)站的支付功能:

用戶點擊支付按鈕 → 調(diào)用支付接口
↓
網(wǎng)絡(luò)超時/服務(wù)器繁忙 → 支付失敗
↓
用戶看到錯誤提示 → 用戶體驗糟糕
可能的結(jié)果:用戶放棄購買、訂單丟失、收入損失

如果有智能重試機(jī)制:

用戶點擊支付按鈕 → 調(diào)用支付接口
↓
第一次失敗 → 等待1秒后自動重試
第二次失敗 → 等待2秒后自動重試  
第三次成功 → 支付完成,用戶無感知

場景二:大文件上傳

在文件管理系統(tǒng)中上傳大文件:

上傳進(jìn)度:[████████████████████████████████████████] 95%
↓
網(wǎng)絡(luò)中斷 → 上傳失敗 → 用戶需要重新上傳整個文件

vs

上傳進(jìn)度:[████████████████████████████████████████] 95%
↓
網(wǎng)絡(luò)中斷 → 自動重試 → 斷點續(xù)傳 → 上傳完成

場景三:微服務(wù)架構(gòu)中的服務(wù)調(diào)用

在微服務(wù)系統(tǒng)中,服務(wù)之間頻繁調(diào)用:

用戶服務(wù) → 調(diào)用訂單服務(wù) → 調(diào)用庫存服務(wù) → 調(diào)用支付服務(wù)

任何一個環(huán)節(jié)的臨時故障都可能導(dǎo)致整個流程失敗
需要智能重試來提高系統(tǒng)的容錯能力

傳統(tǒng)處理方式的痛點

痛點一:簡單粗暴的重試

// 原始的重試方式:固定間隔,沒有策略
asyncfunction simpleRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
    try {
      returnawait fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      awaitnewPromise(resolve => setTimeout(resolve, 1000)); // 固定等待1秒
    }
  }
}

這種方式的問題:

  • 所有錯誤都重試,包括不應(yīng)該重試的(如400錯誤)
  • 固定間隔容易造成"驚群效應(yīng)"
  • 沒有考慮服務(wù)器負(fù)載情況
  • 缺乏靈活性和可配置性

痛點二:沒有指數(shù)退避

// 問題:大量客戶端同時重試,加重服務(wù)器負(fù)擔(dān)
async function badRetry() {
  // 100個客戶端在同一時間重試
  // 第1秒: 100個請求同時發(fā)出
  // 第2秒: 100個請求同時重試  
  // 第3秒: 100個請求同時重試
  // 服務(wù)器壓力巨大!
}

痛點三:錯誤類型不區(qū)分

// 問題:所有錯誤一視同仁
try {
const response = await fetch('/api/data');
if (!response.ok) {
    thrownewError('Request failed');
  }
} catch (error) {
// 不管是404(不存在)還是503(服務(wù)不可用)都重試
// 404重試是浪費,503才需要重試
}

痛點四:缺乏監(jiān)控和反饋

// 問題:重試過程黑盒化
async function fetchData() {
  try {
    return await retryRequest();
  } catch (error) {
    // 用戶不知道重試了幾次、為什么失敗
    console.log('請求失敗'); // 信息太少
  }
}

我們的智能重試機(jī)制

現(xiàn)在讓我們來實現(xiàn)一個功能完備的重試管理器:

class RetryManager {
constructor(options = {}) {
    this.options = {
      maxAttempts: 3,           // 最大重試次數(shù)
      baseDelay: 1000,          // 基礎(chǔ)延遲時間(毫秒)
      maxDelay: 30000,          // 最大延遲時間
      backoffFactor: 2,         // 退避因子(指數(shù)退避)
      jitter: true,             // 是否添加隨機(jī)抖動
      retryCondition: (error) =>true,  // 重試條件判斷函數(shù)
      onRetry: (attempt, error, delay) => {}, // 重試回調(diào)
      onSuccess: (result, attempts) => {}, // 成功回調(diào)
      onFailure: (error, attempts) => {}, // 最終失敗回調(diào)
      timeout: 0,               // 單次請求超時時間(0表示不限制)
      abortSignal: null,        // 取消信號
      ...options
    };
    
    // 統(tǒng)計信息
    this.stats = {
      totalAttempts: 0,
      totalSuccesses: 0,
      totalFailures: 0,
      totalRetries: 0,
      averageAttempts: 0
    };
  }

// 執(zhí)行帶重試的異步函數(shù)
async execute(asyncFunction, ...args) {
    let lastError;
    let attempts = 0;
    const startTime = Date.now();
    
    for (let attempt = 1; attempt <= this.options.maxAttempts; attempt++) {
      attempts = attempt;
      this.stats.totalAttempts++;
      
      try {
        // 檢查是否被取消
        this.checkAbortSignal();
        
        // 執(zhí)行函數(shù)(可能帶超時)
        const result = awaitthis.executeWithTimeout(asyncFunction, ...args);
        
        // 成功統(tǒng)計
        this.stats.totalSuccesses++;
        this.updateAverageAttempts();
        
        // 成功回調(diào)
        this.options.onSuccess(result, attempts);
        
        // 記錄成功日志
        if (attempt > 1) {
          console.log(`? 重試成功: 第${attempt}次嘗試成功,總耗時${Date.now() - startTime}ms`);
        }
        
        return result;
        
      } catch (error) {
        lastError = error;
        
        // 檢查是否應(yīng)該重試此錯誤
        if (!this.shouldRetry(error, attempt)) {
          break;
        }
        
        // 如果不是最后一次嘗試,則等待后重試
        if (attempt < this.options.maxAttempts) {
          const delay = this.calculateDelay(attempt);
          
          // 重試回調(diào)
          this.options.onRetry(attempt, error, delay);
          
          console.log(`?? 第${attempt}次嘗試失敗: ${error.message},${delay}ms后重試`);
          
          // 等待指定時間
          awaitthis.sleep(delay);
          
          this.stats.totalRetries++;
        }
      }
    }
    
    // 所有重試都失敗了
    this.stats.totalFailures++;
    this.updateAverageAttempts();
    
    // 失敗回調(diào)
    this.options.onFailure(lastError, attempts);
    
    console.error(`? 重試失敗: ${attempts}次嘗試后仍然失敗,總耗時${Date.now() - startTime}ms`);
    
    throw lastError;
  }

// 計算延遲時間(指數(shù)退避 + 隨機(jī)抖動)
  calculateDelay(attempt) {
    // 指數(shù)退避: baseDelay * backoffFactor^(attempt-1)
    const exponentialDelay = this.options.baseDelay * Math.pow(this.options.backoffFactor, attempt - 1);
    
    // 限制最大延遲
    const cappedDelay = Math.min(exponentialDelay, this.options.maxDelay);
    
    // 添加隨機(jī)抖動,避免驚群效應(yīng)
    if (this.options.jitter) {
      // 在延遲時間的±25%范圍內(nèi)添加隨機(jī)抖動
      const jitterRange = cappedDelay * 0.25;
      const jitter = (Math.random() - 0.5) * 2 * jitterRange;
      returnMath.max(0, Math.round(cappedDelay + jitter));
    }
    
    return cappedDelay;
  }

// 判斷是否應(yīng)該重試
  shouldRetry(error, attempt) {
    // 檢查是否被取消
    if (this.isAborted()) {
      returnfalse;
    }
    
    // 已經(jīng)是最后一次嘗試
    if (attempt >= this.options.maxAttempts) {
      returnfalse;
    }
    
    // 使用自定義重試條件判斷
    returnthis.options.retryCondition(error, attempt);
  }

// 帶超時的函數(shù)執(zhí)行
async executeWithTimeout(asyncFunction, ...args) {
    if (this.options.timeout <= 0) {
      return asyncFunction(...args);
    }
    
    const timeoutPromise = newPromise((_, reject) => {
      setTimeout(() => {
        reject(newError(`操作超時: 超過${this.options.timeout}ms`));
      }, this.options.timeout);
    });
    
    returnPromise.race([
      asyncFunction(...args),
      timeoutPromise
    ]);
  }

// 檢查取消信號
  checkAbortSignal() {
    if (this.options.abortSignal && this.options.abortSignal.aborted) {
      thrownewError('操作已取消');
    }
  }

// 檢查是否被取消
  isAborted() {
    returnthis.options.abortSignal && this.options.abortSignal.aborted;
  }

// 等待指定時間
  sleep(ms) {
    returnnewPromise(resolve => setTimeout(resolve, ms));
  }

// 更新平均嘗試次數(shù)
  updateAverageAttempts() {
    const totalCompleted = this.stats.totalSuccesses + this.stats.totalFailures;
    if (totalCompleted > 0) {
      this.stats.averageAttempts = (this.stats.totalAttempts / totalCompleted).toFixed(2);
    }
  }

// 獲取統(tǒng)計信息
  getStats() {
    return {
      ...this.stats,
      successRate: this.stats.totalSuccesses + this.stats.totalFailures > 0 ? 
        (this.stats.totalSuccesses / (this.stats.totalSuccesses + this.stats.totalFailures) * 100).toFixed(2) + '%' : 
        '0%'
    };
  }

// 重置統(tǒng)計信息
  resetStats() {
    this.stats = {
      totalAttempts: 0,
      totalSuccesses: 0,
      totalFailures: 0,
      totalRetries: 0,
      averageAttempts: 0
    };
  }

// 靜態(tài)方法:HTTP請求重試
staticasync retryFetch(url, options = {}, retryOptions = {}) {
    const retryManager = new RetryManager({
      retryCondition: (error) => {
        // 網(wǎng)絡(luò)錯誤總是重試
        if (error.name === 'TypeError' && error.message.includes('fetch')) {
          returntrue;
        }
        
        // HTTP狀態(tài)碼判斷
        if (error.status) {
          // 5xx服務(wù)器錯誤 - 重試
          if (error.status >= 500) returntrue;
          
          // 429限流錯誤 - 重試
          if (error.status === 429) returntrue;
          
          // 408請求超時 - 重試
          if (error.status === 408) returntrue;
          
          // 4xx客戶端錯誤 - 不重試
          if (error.status >= 400 && error.status < 500) returnfalse;
        }
        
        returntrue; // 其他情況默認(rèn)重試
      },
      ...retryOptions
    });
    
    return retryManager.execute(async () => {
      const response = await fetch(url, options);
      
      if (!response.ok) {
        const error = newError(`HTTP ${response.status}: ${response.statusText}`);
        error.status = response.status;
        error.response = response;
        throw error;
      }
      
      return response;
    });
  }
}

// 專門的數(shù)據(jù)庫重試管理器
class DatabaseRetryManager extends RetryManager {
constructor(options = {}) {
    super({
      maxAttempts: 5,
      baseDelay: 500,
      maxDelay: 5000,
      retryCondition: (error) => {
        // 數(shù)據(jù)庫相關(guān)的可重試錯誤
        const retryableErrors = [
          'ConnectionError',
          'TimeoutError', 
          'DeadlockError',
          'LockWaitTimeoutError',
          'ConnectionLostError'
        ];
        
        return retryableErrors.some(errorType =>
          error.name.includes(errorType) || error.message.includes(errorType)
        );
      },
      onRetry: (attempt, error, delay) => {
        console.log(`??? 數(shù)據(jù)庫操作重試: 第${attempt}次失敗(${error.message}),${delay}ms后重試`);
      },
      ...options
    });
  }
}

// 專門的API重試管理器
class APIRetryManager extends RetryManager {
constructor(options = {}) {
    super({
      maxAttempts: 3,
      baseDelay: 1000,
      maxDelay: 10000,
      retryCondition: (error) => {
        // 不重試客戶端錯誤(4xx),除了429限流
        if (error.status >= 400 && error.status < 500 && error.status !== 429) {
          returnfalse;
        }
        
        // 其他情況都重試
        returntrue;
      },
      onRetry: (attempt, error, delay) => {
        if (error.status === 429) {
          console.log(`?? API限流重試: 第${attempt}次觸發(fā)限流,${delay}ms后重試`);
        } else {
          console.log(`?? API請求重試: 第${attempt}次失敗(${error.message}),${delay}ms后重試`);
        }
      },
      ...options
    });
  }
}

// 文件上傳重試管理器
class UploadRetryManager extends RetryManager {
constructor(options = {}) {
    super({
      maxAttempts: 5,
      baseDelay: 2000,
      maxDelay: 30000,
      timeout: 60000, // 60秒超時
      retryCondition: (error) => {
        // 網(wǎng)絡(luò)錯誤和服務(wù)器錯誤都重試
        if (error.name === 'TypeError') returntrue;
        if (error.status >= 500) returntrue;
        if (error.status === 408 || error.status === 429) returntrue;
        
        // 超時錯誤重試
        if (error.message.includes('超時') || error.message.includes('timeout')) {
          returntrue;
        }
        
        returnfalse;
      },
      onRetry: (attempt, error, delay) => {
        console.log(`?? 文件上傳重試: 第${attempt}次失敗,${delay}ms后重試上傳`);
      },
      ...options
    });
  }
}

基礎(chǔ)功能展示

讓我們看看這個重試管理器的基本使用:

// 創(chuàng)建基礎(chǔ)重試管理器
const retryManager = new RetryManager({
maxAttempts: 3,
baseDelay: 1000,
backoffFactor: 2,
jitter: true,
onRetry: (attempt, error, delay) => {
    console.log(`重試中: 第${attempt}次失敗,${delay}ms后重試`);
  }
});

// 重試不可靠的網(wǎng)絡(luò)請求
asyncfunction unreliableNetworkCall() {
// 模擬70%的失敗率
if (Math.random() < 0.7) {
    thrownewError('網(wǎng)絡(luò)連接超時');
  }
return { data: '請求成功的數(shù)據(jù)' };
}

try {
const result = await retryManager.execute(unreliableNetworkCall);
console.log('請求成功:', result);
} catch (error) {
console.error('所有重試失敗:', error.message);
}

// 使用靜態(tài)方法快速重試HTTP請求
asyncfunction fetchUserData(userId) {
try {
    const response = await RetryManager.retryFetch(`/api/users/${userId}`, {
      method: 'GET',
      headers: { 'Authorization': 'Bearer token123' }
    }, {
      maxAttempts: 5,
      baseDelay: 2000
    });
    
    returnawait response.json();
  } catch (error) {
    console.error('用戶數(shù)據(jù)獲取失敗:', error.message);
    throw error;
  }
}

// 查看重試統(tǒng)計
console.log('重試統(tǒng)計:', retryManager.getStats());

實際項目應(yīng)用示例

1. 健壯的HTTP客戶端

class RobustHttpClient {
constructor(options = {}) {
    this.baseURL = options.baseURL || '';
    this.defaultHeaders = options.headers || {};
    this.timeout = options.timeout || 30000;
    
    // 為不同類型的請求配置不同的重試策略
    this.retryManagers = {
      // GET請求:讀操作,可以多次重試
      GET: new APIRetryManager({
        maxAttempts: 5,
        baseDelay: 1000,
        maxDelay: 10000
      }),
      
      // POST請求:寫操作,需要謹(jǐn)慎重試
      POST: new APIRetryManager({
        maxAttempts: 3,
        baseDelay: 2000,
        retryCondition: (error) => {
          // 只重試網(wǎng)絡(luò)錯誤和5xx服務(wù)器錯誤
          if (error.name === 'TypeError') returntrue;
          if (error.status >= 500) returntrue;
          returnfalse;
        }
      }),
      
      // PUT/DELETE請求:冪等操作,可以重試
      PUT: new APIRetryManager({
        maxAttempts: 4,
        baseDelay: 1500
      }),
      
      DELETE: new APIRetryManager({
        maxAttempts: 4,
        baseDelay: 1500
      })
    };
    
    // 請求攔截器
    this.requestInterceptors = [];
    this.responseInterceptors = [];
    
    // 統(tǒng)計信息
    this.stats = {
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      totalRetries: 0
    };
  }

// 添加請求攔截器
  addRequestInterceptor(interceptor) {
    this.requestInterceptors.push(interceptor);
  }

// 添加響應(yīng)攔截器
  addResponseInterceptor(interceptor) {
    this.responseInterceptors.push(interceptor);
  }

// 通用請求方法
async request(config) {
    // 應(yīng)用請求攔截器
    let processedConfig = { ...config };
    for (const interceptor ofthis.requestInterceptors) {
      processedConfig = await interceptor(processedConfig);
    }
    
    // 構(gòu)建完整的請求配置
    const requestConfig = this.buildRequestConfig(processedConfig);
    
    // 選擇重試管理器
    const retryManager = this.retryManagers[requestConfig.method.toUpperCase()] || 
                         this.retryManagers.GET;
    
    this.stats.totalRequests++;
    
    try {
      const response = await retryManager.execute(async () => {
        returnthis.executeRequest(requestConfig);
      });
      
      // 應(yīng)用響應(yīng)攔截器
      let processedResponse = response;
      for (const interceptor ofthis.responseInterceptors) {
        processedResponse = await interceptor(processedResponse);
      }
      
      this.stats.successfulRequests++;
      this.stats.totalRetries += (response._retryCount || 0);
      
      return processedResponse;
      
    } catch (error) {
      this.stats.failedRequests++;
      this.stats.totalRetries += (error._retryCount || 0);
      throw error;
    }
  }

// 執(zhí)行實際的HTTP請求
async executeRequest(config) {
    const url = config.url.startsWith('http') ? config.url : this.baseURL + config.url;
    
    // 添加取消信號支持
    const controller = new AbortController();
    if (config.timeout) {
      setTimeout(() => controller.abort(), config.timeout);
    }
    
    const response = await fetch(url, {
      method: config.method,
      headers: config.headers,
      body: config.body,
      signal: controller.signal,
      ...config.fetchOptions
    });
    
    // 檢查響應(yīng)狀態(tài)
    if (!response.ok) {
      const error = newError(`HTTP ${response.status}: ${response.statusText}`);
      error.status = response.status;
      error.response = response;
      throw error;
    }
    
    // 解析響應(yīng)數(shù)據(jù)
    const contentType = response.headers.get('content-type');
    let data;
    
    if (contentType && contentType.includes('application/json')) {
      data = await response.json();
    } elseif (contentType && contentType.includes('text/')) {
      data = await response.text();
    } else {
      data = await response.blob();
    }
    
    return {
      data,
      status: response.status,
      statusText: response.statusText,
      headers: Object.fromEntries(response.headers.entries()),
      config
    };
  }

// 構(gòu)建請求配置
  buildRequestConfig(config) {
    return {
      method: config.method || 'GET',
      url: config.url,
      headers: {
        'Content-Type': 'application/json',
        ...this.defaultHeaders,
        ...config.headers
      },
      body: config.data ? JSON.stringify(config.data) : config.body,
      timeout: config.timeout || this.timeout,
      fetchOptions: config.fetchOptions || {}
    };
  }

// 便捷方法
asyncget(url, config = {}) {
    returnthis.request({ method: 'GET', url, ...config });
  }

async post(url, data, config = {}) {
    returnthis.request({ method: 'POST', url, data, ...config });
  }

async put(url, data, config = {}) {
    returnthis.request({ method: 'PUT', url, data, ...config });
  }

asyncdelete(url, config = {}) {
    returnthis.request({ method: 'DELETE', url, ...config });
  }

// 上傳文件
async upload(url, file, options = {}) {
    const uploadRetryManager = new UploadRetryManager({
      onRetry: (attempt, error, delay) => {
        if (options.onRetry) {
          options.onRetry(attempt, error, delay);
        }
      }
    });
    
    return uploadRetryManager.execute(async () => {
      const formData = new FormData();
      formData.append(options.fieldName || 'file', file);
      
      // 添加額外字段
      if (options.fields) {
        Object.entries(options.fields).forEach(([key, value]) => {
          formData.append(key, value);
        });
      }
      
      returnthis.executeRequest({
        method: 'POST',
        url,
        body: formData,
        headers: {
          // 不設(shè)置Content-Type,讓瀏覽器自動設(shè)置multipart/form-data
          ...this.defaultHeaders,
          ...options.headers
        },
        timeout: options.timeout || 60000
      });
    });
  }

// 批量請求(并發(fā)控制)
async batchRequest(requests, options = {}) {
    const { concurrency = 5, failFast = false } = options;
    const results = [];
    
    // 分批處理請求
    for (let i = 0; i < requests.length; i += concurrency) {
      const batch = requests.slice(i, i + concurrency);
      
      const batchPromises = batch.map(async (requestConfig, index) => {
        try {
          const result = awaitthis.request(requestConfig);
          return { index: i + index, success: true, data: result };
        } catch (error) {
          if (failFast) {
            throw error;
          }
          return { index: i + index, success: false, error };
        }
      });
      
      const batchResults = awaitPromise.all(batchPromises);
      results.push(...batchResults);
    }
    
    return results.sort((a, b) => a.index - b.index);
  }

// 獲取統(tǒng)計信息
  getStats() {
    return {
      ...this.stats,
      successRate: this.stats.totalRequests > 0 ? 
        (this.stats.successfulRequests / this.stats.totalRequests * 100).toFixed(2) + '%' : 
        '0%',
      averageRetries: this.stats.totalRequests > 0 ? 
        (this.stats.totalRetries / this.stats.totalRequests).toFixed(2) : 
        '0'
    };
  }

// 健康檢查
async healthCheck(endpoint = '/health') {
    try {
      const response = awaitthis.get(endpoint, { timeout: 5000 });
      return {
        healthy: true,
        status: response.status,
        data: response.data,
        timestamp: newDate().toISOString()
      };
    } catch (error) {
      return {
        healthy: false,
        error: error.message,
        timestamp: newDate().toISOString()
      };
    }
  }
}

// 使用示例
const httpClient = new RobustHttpClient({
baseURL: 'https://api.example.com',
headers: {
    'Authorization': 'Bearer your-token-here'
  },
timeout: 30000
});

// 添加請求攔截器(自動添加時間戳)
httpClient.addRequestInterceptor(async (config) => {
console.log(`?? 發(fā)送請求: ${config.method} ${config.url}`);
  config.headers['X-Request-Time'] = Date.now();
return config;
});

// 添加響應(yīng)攔截器(記錄響應(yīng)時間)
httpClient.addResponseInterceptor(async (response) => {
const requestTime = response.config.headers['X-Request-Time'];
const responseTime = Date.now() - requestTime;
console.log(`? 請求完成: ${response.config.method} ${response.config.url} (${responseTime}ms)`);
return response;
});

// 使用示例
asyncfunction demonstrateHttpClient() {
try {
    // GET請求
    const userData = await httpClient.get('/users/123');
    console.log('用戶數(shù)據(jù):', userData.data);
    
    // POST請求
    const newUser = await httpClient.post('/users', {
      name: '張三',
      email: 'zhangsan@example.com'
    });
    console.log('創(chuàng)建用戶:', newUser.data);
    
    // 文件上傳
    const fileInput = document.getElementById('file-input');
    if (fileInput && fileInput.files[0]) {
      const uploadResult = await httpClient.upload('/upload', fileInput.files[0], {
        fields: { description: '用戶頭像' },
        onRetry: (attempt, error, delay) => {
          console.log(`上傳重試: 第${attempt}次失敗,${delay}ms后重試`);
        }
      });
      console.log('上傳成功:', uploadResult.data);
    }
    
    // 批量請求
    const batchRequests = [
      { method: 'GET', url: '/users/1' },
      { method: 'GET', url: '/users/2' },
      { method: 'GET', url: '/users/3' }
    ];
    
    const batchResults = await httpClient.batchRequest(batchRequests, {
      concurrency: 2
    });
    
    console.log('批量請求結(jié)果:', batchResults);
    
    // 健康檢查
    const health = await httpClient.healthCheck();
    console.log('服務(wù)健康狀態(tài):', health);
    
    // 查看統(tǒng)計信息
    console.log('HTTP客戶端統(tǒng)計:', httpClient.getStats());
    
  } catch (error) {
    console.error('請求失敗:', error.message);
  }
}

// 定期健康檢查
setInterval(async () => {
const health = await httpClient.healthCheck();
if (!health.healthy) {
    console.warn('?? 服務(wù)不健康:', health.error);
  }
}, 60000); // 每分鐘檢查一次

2. 分布式任務(wù)處理系統(tǒng)

class DistributedTaskProcessor {
constructor(options = {}) {
    this.options = {
      maxConcurrency: options.maxConcurrency || 5,
      taskTimeout: options.taskTimeout || 30000,
      retryDelay: options.retryDelay || 1000,
      maxRetries: options.maxRetries || 3,
      ...options
    };
    
    // 任務(wù)隊列
    this.taskQueue = [];
    this.runningTasks = newMap();
    this.completedTasks = [];
    this.failedTasks = [];
    
    // 重試管理器
    this.retryManager = new RetryManager({
      maxAttempts: this.options.maxRetries,
      baseDelay: this.options.retryDelay,
      timeout: this.options.taskTimeout,
      onRetry: (attempt, error, delay) => {
        console.log(`?? 任務(wù)重試: 第${attempt}次失敗(${error.message}),${delay}ms后重試`);
      }
    });
    
    // 任務(wù)統(tǒng)計
    this.stats = {
      totalTasks: 0,
      completedTasks: 0,
      failedTasks: 0,
      averageExecutionTime: 0
    };
    
    this.isProcessing = false;
  }

// 添加任務(wù)
  addTask(task) {
    const taskId = this.generateTaskId();
    const taskWrapper = {
      id: taskId,
      task: task.fn,
      data: task.data || {},
      priority: task.priority || 0,
      createdAt: newDate(),
      retryCount: 0,
      maxRetries: task.maxRetries || this.options.maxRetries,
      timeout: task.timeout || this.options.taskTimeout,
      onProgress: task.onProgress,
      onComplete: task.onComplete,
      onError: task.onError
    };
    
    this.taskQueue.push(taskWrapper);
    this.stats.totalTasks++;
    
    // 按優(yōu)先級排序
    this.taskQueue.sort((a, b) => b.priority - a.priority);
    
    console.log(`? 任務(wù)已添加: ${taskId} (優(yōu)先級: ${taskWrapper.priority})`);
    
    // 如果沒在處理,開始處理
    if (!this.isProcessing) {
      this.processQueue();
    }
    
    return taskId;
  }

// 批量添加任務(wù)
  addTasks(tasks) {
    return tasks.map(task =>this.addTask(task));
  }

// 處理任務(wù)隊列
async processQueue() {
    if (this.isProcessing) return;
    
    this.isProcessing = true;
    console.log('?? 開始處理任務(wù)隊列');
    
    while (this.taskQueue.length > 0 || this.runningTasks.size > 0) {
      // 啟動新任務(wù)(在并發(fā)限制內(nèi))
      while (this.taskQueue.length > 0 && 
             this.runningTasks.size < this.options.maxConcurrency) {
        const task = this.taskQueue.shift();
        this.executeTask(task);
      }
      
      // 等待一小段時間再檢查
      awaitthis.sleep(100);
    }
    
    this.isProcessing = false;
    console.log('? 任務(wù)隊列處理完成');
    
    // 輸出最終統(tǒng)計
    this.printStats();
  }

// 執(zhí)行單個任務(wù)
async executeTask(taskWrapper) {
    const { id, task, data, timeout, onProgress, onComplete, onError } = taskWrapper;
    
    this.runningTasks.set(id, taskWrapper);
    console.log(`?? 開始執(zhí)行任務(wù): ${id}`);
    
    const startTime = Date.now();
    
    try {
      // 使用重試管理器執(zhí)行任務(wù)
      const result = awaitthis.retryManager.execute(async () => {
        // 創(chuàng)建任務(wù)執(zhí)行上下文
        const taskContext = {
          id,
          data,
          progress: (percent, message) => {
            if (onProgress) {
              onProgress(percent, message);
            }
            console.log(`?? 任務(wù)進(jìn)度 ${id}: ${percent}% - ${message}`);
          },
          isCancelled: () =>false// 可以擴(kuò)展為支持任務(wù)取消
        };
        
        returnawait task(taskContext);
      });
      
      // 任務(wù)完成
      const executionTime = Date.now() - startTime;
      this.onTaskComplete(taskWrapper, result, executionTime);
      
      if (onComplete) {
        onComplete(result);
      }
      
    } catch (error) {
      // 任務(wù)失敗
      const executionTime = Date.now() - startTime;
      this.onTaskFailed(taskWrapper, error, executionTime);
      
      if (onError) {
        onError(error);
      }
    } finally {
      this.runningTasks.delete(id);
    }
  }

// 任務(wù)完成處理
  onTaskComplete(taskWrapper, result, executionTime) {
    const completedTask = {
      ...taskWrapper,
      result,
      executionTime,
      completedAt: newDate(),
      status: 'completed'
    };
    
    this.completedTasks.push(completedTask);
    this.stats.completedTasks++;
    
    // 更新平均執(zhí)行時間
    this.updateAverageExecutionTime(executionTime);
    
    console.log(`? 任務(wù)完成: ${taskWrapper.id} (耗時: ${executionTime}ms)`);
  }

// 任務(wù)失敗處理
  onTaskFailed(taskWrapper, error, executionTime) {
    const failedTask = {
      ...taskWrapper,
      error: error.message,
      executionTime,
      failedAt: newDate(),
      status: 'failed'
    };
    
    this.failedTasks.push(failedTask);
    this.stats.failedTasks++;
    
    console.error(`? 任務(wù)失敗: ${taskWrapper.id} (耗時: ${executionTime}ms) - ${error.message}`);
  }

// 獲取任務(wù)狀態(tài)
  getTaskStatus(taskId) {
    // 檢查正在運行的任務(wù)
    if (this.runningTasks.has(taskId)) {
      return {
        status: 'running',
        task: this.runningTasks.get(taskId)
      };
    }
    
    // 檢查已完成的任務(wù)
    const completed = this.completedTasks.find(t => t.id === taskId);
    if (completed) {
      return { status: 'completed', task: completed };
    }
    
    // 檢查失敗的任務(wù)
    const failed = this.failedTasks.find(t => t.id === taskId);
    if (failed) {
      return { status: 'failed', task: failed };
    }
    
    // 檢查隊列中的任務(wù)
    const queued = this.taskQueue.find(t => t.id === taskId);
    if (queued) {
      return { status: 'queued', task: queued };
    }
    
    return { status: 'not_found' };
  }

// 取消任務(wù)
  cancelTask(taskId) {
    // 從隊列中移除
    const queueIndex = this.taskQueue.findIndex(t => t.id === taskId);
    if (queueIndex !== -1) {
      this.taskQueue.splice(queueIndex, 1);
      console.log(`?? 任務(wù)已取消: ${taskId} (從隊列中移除)`);
      returntrue;
    }
    
    // 正在運行的任務(wù)標(biāo)記為取消(需要任務(wù)本身支持檢查取消狀態(tài))
    if (this.runningTasks.has(taskId)) {
      const task = this.runningTasks.get(taskId);
      task.cancelled = true;
      console.log(`?? 任務(wù)已標(biāo)記取消: ${taskId} (正在運行,等待任務(wù)檢查取消狀態(tài))`);
      returntrue;
    }
    
    returnfalse;
  }

// 暫停任務(wù)處理
  pause() {
    this.isProcessing = false;
    console.log('?? 任務(wù)處理已暫停');
  }

// 恢復(fù)任務(wù)處理
  resume() {
    if (!this.isProcessing) {
      console.log('?? 任務(wù)處理已恢復(fù)');
      this.processQueue();
    }
  }

// 獲取統(tǒng)計信息
  getStats() {
    return {
      ...this.stats,
      queuedTasks: this.taskQueue.length,
      runningTasks: this.runningTasks.size,
      successRate: this.stats.totalTasks > 0 ? 
        (this.stats.completedTasks / this.stats.totalTasks * 100).toFixed(2) + '%' : 
        '0%'
    };
  }

// 輸出統(tǒng)計信息
  printStats() {
    const stats = this.getStats();
    console.log('\n?? 任務(wù)處理統(tǒng)計:');
    console.log(`總?cè)蝿?wù)數(shù): ${stats.totalTasks}`);
    console.log(`已完成: ${stats.completedTasks}`);
    console.log(`失敗: ${stats.failedTasks}`);
    console.log(`成功率: ${stats.successRate}`);
    console.log(`平均執(zhí)行時間: ${stats.averageExecutionTime}ms`);
  }

// 工具方法
  generateTaskId() {
    return`task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  sleep(ms) {
    returnnewPromise(resolve => setTimeout(resolve, ms));
  }

  updateAverageExecutionTime(executionTime) {
    const totalCompleted = this.stats.completedTasks;
    if (totalCompleted === 1) {
      this.stats.averageExecutionTime = executionTime;
    } else {
      this.stats.averageExecutionTime = Math.round(
        (this.stats.averageExecutionTime * (totalCompleted - 1) + executionTime) / totalCompleted
      );
    }
  }
}

// 使用示例
const taskProcessor = new DistributedTaskProcessor({
maxConcurrency: 3,
taskTimeout: 10000,
maxRetries: 2
});

// 定義一些示例任務(wù)
const tasks = [
  {
    fn: async (context) => {
      context.progress(0, '開始處理圖片');
      
      // 模擬圖片處理
      for (let i = 0; i <= 100; i += 10) {
        context.progress(i, `處理進(jìn)度 ${i}%`);
        awaitnewPromise(resolve => setTimeout(resolve, 100));
        
        // 模擬隨機(jī)失敗
        if (i === 50 && Math.random() < 0.3) {
          thrownewError('圖片處理失敗');
        }
      }
      
      return { processed: true, size: '1024x768' };
    },
    data: { imageId: 'img_001', format: 'jpg' },
    priority: 1,
    onComplete: (result) => {
      console.log('??? 圖片處理完成:', result);
    },
    onError: (error) => {
      console.error('??? 圖片處理失敗:', error.message);
    }
  },

  {
    fn: async (context) => {
      context.progress(0, '開始數(shù)據(jù)同步');
      
      // 模擬數(shù)據(jù)同步
      const steps = ['連接數(shù)據(jù)庫', '讀取數(shù)據(jù)', '轉(zhuǎn)換格式', '寫入目標(biāo)', '驗證結(jié)果'];
      
      for (let i = 0; i < steps.length; i++) {
        context.progress((i / steps.length) * 100, steps[i]);
        awaitnewPromise(resolve => setTimeout(resolve, 200));
        
        // 模擬偶發(fā)錯誤
        if (i === 2 && Math.random() < 0.2) {
          thrownewError('數(shù)據(jù)轉(zhuǎn)換失敗');
        }
      }
      
      return { syncedRecords: 1500, duration: '2.1s' };
    },
    data: { source: 'database_a', target: 'database_b' },
    priority: 2,
    onComplete: (result) => {
      console.log('?? 數(shù)據(jù)同步完成:', result);
    }
  },

  {
    fn: async (context) => {
      context.progress(0, '開始文件上傳');
      
      // 模擬文件上傳
      for (let i = 0; i <= 100; i += 5) {
        context.progress(i, `上傳進(jìn)度 ${i}%`);
        awaitnewPromise(resolve => setTimeout(resolve, 50));
      }
      
      return { uploaded: true, url: 'https://cdn.example.com/file123.pdf' };
    },
    data: { fileName: 'report.pdf', size: '2.5MB' },
    priority: 0,
    onComplete: (result) => {
      console.log('?? 文件上傳完成:', result);
    }
  }
];

// 添加任務(wù)到處理器
console.log('添加任務(wù)到處理隊列...');
const taskIds = taskProcessor.addTasks(tasks);

// 監(jiān)控任務(wù)狀態(tài)
setTimeout(() => {
  taskIds.forEach(id => {
    const status = taskProcessor.getTaskStatus(id);
    console.log(`任務(wù)狀態(tài) ${id}: ${status.status}`);
  });
}, 3000);

// 5秒后輸出最終統(tǒng)計
setTimeout(() => {
console.log('最終統(tǒng)計信息:', taskProcessor.getStats());
}, 8000);

性能優(yōu)化和最佳實踐

1. 智能退避策略

class AdaptiveRetryManager extends RetryManager {
constructor(options = {}) {
    super(options);
    this.successHistory = [];
    this.errorPatterns = newMap();
  }

// 自適應(yīng)延遲計算
  calculateDelay(attempt, error) {
    // 基礎(chǔ)指數(shù)退避
    let delay = super.calculateDelay(attempt);
    
    // 根據(jù)錯誤類型調(diào)整
    if (error && error.status === 429) {
      // 限流錯誤:增加延遲
      delay *= 2;
    } elseif (error && error.status >= 500) {
      // 服務(wù)器錯誤:根據(jù)歷史成功率調(diào)整
      const recentSuccessRate = this.getRecentSuccessRate();
      if (recentSuccessRate < 0.5) {
        delay *= 1.5; // 成功率低時增加延遲
      }
    }
    
    return delay;
  }

// 獲取最近的成功率
  getRecentSuccessRate() {
    const recentResults = this.successHistory.slice(-10);
    if (recentResults.length === 0) return1;
    
    const successes = recentResults.filter(result => result).length;
    return successes / recentResults.length;
  }

// 記錄執(zhí)行結(jié)果
  recordResult(success, error = null) {
    this.successHistory.push(success);
    if (this.successHistory.length > 100) {
      this.successHistory.shift();
    }
    
    if (!success && error) {
      const pattern = this.getErrorPattern(error);
      const count = this.errorPatterns.get(pattern) || 0;
      this.errorPatterns.set(pattern, count + 1);
    }
  }

  getErrorPattern(error) {
    return`${error.name}:${error.status || 'unknown'}`;
  }
}

2. 斷路器模式

class CircuitBreakerRetryManager extends RetryManager {
constructor(options = {}) {
    super(options);
    
    this.circuitBreaker = {
      state: 'CLOSED', // CLOSED, OPEN, HALF_OPEN
      failureCount: 0,
      failureThreshold: options.failureThreshold || 5,
      timeoutDuration: options.timeoutDuration || 60000,
      nextAttempt: 0,
      successCount: 0
    };
  }

async execute(asyncFunction, ...args) {
    // 檢查斷路器狀態(tài)
    if (this.circuitBreaker.state === 'OPEN') {
      if (Date.now() < this.circuitBreaker.nextAttempt) {
        thrownewError('斷路器開啟狀態(tài),請稍后重試');
      } else {
        this.circuitBreaker.state = 'HALF_OPEN';
        this.circuitBreaker.successCount = 0;
      }
    }
    
    try {
      const result = awaitsuper.execute(asyncFunction, ...args);
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  onSuccess() {
    this.circuitBreaker.failureCount = 0;
    
    if (this.circuitBreaker.state === 'HALF_OPEN') {
      this.circuitBreaker.successCount++;
      if (this.circuitBreaker.successCount >= 2) {
        this.circuitBreaker.state = 'CLOSED';
        console.log('?? 斷路器已關(guān)閉,恢復(fù)正常');
      }
    }
  }

  onFailure() {
    this.circuitBreaker.failureCount++;
    
    if (this.circuitBreaker.state === 'HALF_OPEN') {
      this.openCircuit();
    } elseif (this.circuitBreaker.failureCount >= this.circuitBreaker.failureThreshold) {
      this.openCircuit();
    }
  }

  openCircuit() {
    this.circuitBreaker.state = 'OPEN';
    this.circuitBreaker.nextAttempt = Date.now() + this.circuitBreaker.timeoutDuration;
    console.log(`? 斷路器已開啟,${this.circuitBreaker.timeoutDuration / 1000}秒后重試`);
  }
  
  getCircuitState() {
    return {
      state: this.circuitBreaker.state,
      failureCount: this.circuitBreaker.failureCount,
      nextAttempt: this.circuitBreaker.nextAttempt
    };
  }
}

3. 并發(fā)控制

class ConcurrentRetryManager {
constructor(maxConcurrency = 5) {
    this.maxConcurrency = maxConcurrency;
    this.running = 0;
    this.queue = [];
  }

async execute(retryManager, asyncFunction, ...args) {
    returnnewPromise((resolve, reject) => {
      this.queue.push({
        retryManager,
        asyncFunction,
        args,
        resolve,
        reject
      });
      
      this.processQueue();
    });
  }

async processQueue() {
    if (this.running >= this.maxConcurrency || this.queue.length === 0) {
      return;
    }
    
    this.running++;
    const task = this.queue.shift();
    
    try {
      const result = await task.retryManager.execute(task.asyncFunction, ...task.args);
      task.resolve(result);
    } catch (error) {
      task.reject(error);
    } finally {
      this.running--;
      this.processQueue();
    }
  }
}

總結(jié)

通過我們自制的異步重試機(jī)制,我們實現(xiàn)了:

核心優(yōu)勢:

  • 智能重試:指數(shù)退避+隨機(jī)抖動,避免驚群效應(yīng)
  • 靈活配置:可配置的重試條件、次數(shù)、延遲策略
  • 錯誤區(qū)分:智能判斷哪些錯誤需要重試,哪些不需要
  • 詳細(xì)監(jiān)控:完整的重試過程監(jiān)控和統(tǒng)計

強大功能:

  • ? 指數(shù)退避算法:避免給服務(wù)器造成過大壓力
  • ? 隨機(jī)抖動:防止多客戶端同時重試
  • ? 超時控制:防止單個請求占用過長時間
  • ? 取消支持:支持中途取消重試操作
  • ? 統(tǒng)計分析:詳細(xì)的成功率和性能統(tǒng)計

實際應(yīng)用場景:

  • ? HTTP客戶端:健壯的網(wǎng)絡(luò)請求處理
  • ? 任務(wù)處理:分布式任務(wù)的可靠執(zhí)行
  • ? 文件上傳:大文件上傳的斷點續(xù)傳
  • ? 數(shù)據(jù)庫操作:數(shù)據(jù)庫連接的容錯處理

高級特性:

  • ? 斷路器模式:服務(wù)降級和快速失敗
  • ? 自適應(yīng)策略:根據(jù)歷史情況調(diào)整重試參數(shù)
  • ? 并發(fā)控制:避免過多并發(fā)請求
  • ? 批量處理:高效處理大量異步任務(wù)

這個重試機(jī)制不僅解決了網(wǎng)絡(luò)不穩(wěn)定環(huán)境下的可靠性問題,更重要的是提供了企業(yè)級應(yīng)用所需的監(jiān)控、統(tǒng)計和控制能力。無論是簡單的API調(diào)用還是復(fù)雜的分布式任務(wù)處理,都能提供穩(wěn)定可靠的重試保障。

掌握了這個工具,你的應(yīng)用就能在各種不穩(wěn)定的網(wǎng)絡(luò)環(huán)境中穩(wěn)如磐石,為用戶提供始終可靠的服務(wù)體驗!

責(zé)任編輯:武曉燕 來源: 前端達(dá)人
相關(guān)推薦

2025-03-03 03:00:00

2018-05-07 10:20:38

Kafka存儲機(jī)制

2013-04-24 10:31:44

公有云云安全

2010-12-28 20:04:10

網(wǎng)絡(luò)的可靠性網(wǎng)絡(luò)解決方案可靠性

2022-11-14 08:19:59

重試機(jī)制Kafka

2009-04-08 10:23:00

軟交換網(wǎng)絡(luò)可靠

2022-03-07 08:13:06

MQ消息可靠性異步通訊

2010-12-28 19:50:21

可靠性產(chǎn)品可靠性

2023-07-07 08:16:53

Redis持久化

2010-12-28 20:21:26

2024-09-25 08:32:05

2025-09-30 01:55:00

SpringWebClientHTTP

2014-02-13 10:30:13

云計算迪普科技DPX19000

2020-07-19 15:39:37

Python開發(fā)工具

2025-02-26 10:49:14

2021-02-20 10:02:22

Spring重試機(jī)制Java

2021-10-29 16:55:47

遠(yuǎn)程網(wǎng)絡(luò)網(wǎng)絡(luò)管理網(wǎng)絡(luò)連接

2019-08-30 12:10:05

磁盤數(shù)據(jù)可靠性RAID

2022-05-06 07:44:10

微服務(wù)系統(tǒng)設(shè)計重試機(jī)制

2020-12-06 14:51:23

物聯(lián)網(wǎng)可靠性IOT
點贊
收藏

51CTO技術(shù)棧公眾號

欧美精品777| 国精品**一区二区三区在线蜜桃| 国内精品久久久久久久影视蜜臀 | 亚洲精品第二页| 亚洲三级中文字幕| 丝袜诱惑制服诱惑色一区在线观看| 一区二区三区在线观看动漫| 91精品国产91久久久| 亚洲小视频网站| 青草视频在线免费直播| 日韩在线a电影| 亚洲精品国产拍免费91在线| 丁香六月激情网| 久久av少妇| 国产精品资源在线| 奇米4444一区二区三区| 成年人看片网站| 三级中文字幕在线观看| 成人av午夜电影| 国产精品永久在线| 男人天堂中文字幕| 天天射—综合中文网| 日韩av在线不卡| 五月天丁香花婷婷| 男人皇宫亚洲男人2020| 亚洲黄色av一区| 国产91精品入口17c| 久久久久久久久久综合| 成人短片线上看| 亚洲第一区中文99精品| 亚洲欧美日本一区二区| 校园春色亚洲色图| 国产精品久久影院| 久久综合入口| 亚洲av无码一区二区三区性色| 欧美日韩亚洲一区| 久久精品久久精品亚洲人| 亚洲高清av一区二区三区| 欧美激情喷水| 精品国产999| 中文字幕色呦呦| 无遮挡的视频在线观看| 久久久久国产一区二区三区四区| 国产精品毛片a∨一区二区三区|国| 中文字幕12页| 欧洲av不卡| 午夜精品久久久久久久| 国产欧美久久久久| 成视频免费观看在线看| 中文字幕欧美区| 日韩三级电影网站| 黄色在线观看网| 91丨九色丨蝌蚪丨老版| 国产精品视频一| 欧美一区免费看| 小处雏高清一区二区三区| 午夜精品福利在线| 女人被男人躁得好爽免费视频| 欧美理论在线观看| 精品一区二区三区久久| 国内精品视频久久| 久久高清免费视频| 国产高清久久| 久久精品视频导航| 国产精品丝袜一区二区| 四虎国产精品免费观看| 精品少妇一区二区三区| 亚洲综合中文网| 91久久精品无嫩草影院| 岛国av在线不卡| ww国产内射精品后入国产| 嗯~啊~轻一点视频日本在线观看| 国产精品第四页| 中文字幕人成一区| av毛片在线播放| 亚洲国产精品一区二区www在线| 神马影院午夜我不卡| 成人一区二区不卡免费| 中文字幕一区免费在线观看| 四虎永久免费网站| 亚洲精品视频网| 免播放器亚洲一区| 成人国产精品久久久| 性一交一乱一色一视频麻豆| av在线不卡网| 日韩欧美亚洲日产国| 搡老岳熟女国产熟妇| 久久综合九色综合欧美亚洲| 国产久一道中文一区| 亚洲大尺度在线观看| 亚洲高清毛片| 国产97在线|日韩| 国产精品一区二区免费视频| 国产69精品一区二区亚洲孕妇| 成人欧美一区二区三区黑人孕妇| 国产亚洲欧美日韩高清| 麻豆免费看一区二区三区| 国产97在线播放| 国产又粗又黄又爽| 久久99精品一区二区三区三区| 国产91色在线|免| 国产一区二区三区中文字幕 | 国产成人免费在线| 97av在线视频| 91极品身材尤物theporn| 国产成人精品三级| 成人久久18免费网站漫画| 在线视频精品免费| 国产精品一区二区三区99| 成人在线观看视频网站| 亚洲 欧美 自拍偷拍| 欧美—级在线免费片| 日韩电影免费观看在| 国产一二三在线观看| 国产偷国产偷精品高清尤物| 中文字幕色呦呦| av伦理在线| 欧美日韩一区二区不卡| 91最新在线观看| a看欧美黄色女同性恋| 中文字幕久久亚洲| 久久久久久成人网| 精品视频在线观看免费观看| 亚洲精品一区二三区不卡| 美国黄色一级毛片| 风间由美性色一区二区三区四区 | 亚洲AV无码乱码国产精品牛牛| 国产98色在线|日韩| 国产伦精品一区二区三区四区免费| 天天操天天干天天插| 亚洲天堂网中文字| 久久艳妇乳肉豪妇荡乳av| 国产精品一卡二卡三卡| 在线日韩av片| 亚洲一区二区三区四区五区六区| 国产欧美日韩在线观看视频| 中文字幕9999| 国产午夜麻豆影院在线观看| av不卡免费电影| www.欧美黄色| 美女国产精品久久久| 色视频www在线播放国产成人| 美女毛片在线观看| 亚洲毛片av| 亚洲最大的免费| 香蕉视频国产在线观看| 欧美性生活久久| 久久久视频6r| 欧美三级网页| 99高清视频有精品视频| 免费理论片在线观看播放老| 天天av天天翘天天综合网| 熟妇高潮一区二区| 一区视频在线| 精品不卡在线| 激情aⅴ欧美一区二区欲海潮 | 91久久久久国产一区二区| 高清在线观看日韩| 无码人妻精品一区二区蜜桃百度| 搞黄视频在线观看| 在线视频中文字幕一区二区| 国产精品999.| 高清精品视频| 久久乐国产精品| 在线视频免费观看一区| 国产精品麻豆视频| 日本一二区免费| 91精品电影| www国产亚洲精品| jizz一区二区三区| 日韩成人性视频| 免费观看成人毛片| 国产欧美日韩一区二区三区在线观看 | 久久久999久久久| 国产精品卡一卡二卡三| 小早川怜子一区二区三区| 在线免费观看日本欧美爱情大片| 国产成人精品视频在线| 波多野结衣在线影院| 欧美美女bb生活片| 国产在线综合网| 捆绑变态av一区二区三区| 欧美日韩一区二区视频在线| av成人亚洲| 久久国产视频网站| 天天射天天色天天干| 亚洲自拍偷拍网站| 爱爱的免费视频| 美女任你摸久久| 亚洲电影网站| 日本一区二区乱| **欧美日韩vr在线| 99中文字幕一区| 欧美羞羞免费网站| 欧美日韩精品在线观看视频| 99视频超级精品| 999精品视频在线| 国产精品va| www日韩av| yw.尤物在线精品视频| 欧美理论片在线观看| 男人的天堂在线视频| 一本一本久久a久久精品综合麻豆 一本一道波多野结衣一区二区 | 在线精品视频小说1| 国产传媒免费在线观看| 91原创在线视频| 欧美日韩亚洲一| 香蕉久久夜色精品国产更新时间| 性亚洲最疯狂xxxx高清| 91网页在线观看| 亚洲成人中文字幕| 91九色蝌蚪91por成人| 欧美日韩性视频在线| 免费在线黄色网| 国产视频911| 2一3sex性hd| 国产在线精品国自产拍免费| 国产精品99久久免费黑人人妻| 国产探花一区| 国产综合动作在线观看| 黄色av电影在线观看| 欧美一级视频精品观看| www.com亚洲| 午夜视频一区二区| 亚洲精品视频久久久| 国产一区成人| 日韩精品久久一区二区| 国产毛片精品| 91亚洲精品久久久| 123区在线| 久久国产天堂福利天堂| 成年人免费在线视频| 亚洲女人天堂成人av在线| 蜜桃久久一区二区三区| 91精品综合久久久久久| 在线免费a视频| 在线观看av不卡| 欧美一区二区三区不卡视频| 国产亚洲精久久久久久| 国产草草浮力影院| 丁香婷婷综合五月| 丰满少妇中文字幕| 国产一区二区三区av电影| 久久人人爽av| 蜜桃久久久久久| 久久久久免费精品| 久久亚洲风情| 青草全福视在线| 青青草久久爱| 国产伦视频一区二区三区| 亚洲精品不卡在线观看 | а√天堂资源官网在线资源| 欧美日韩ab片| 四季久久免费一区二区三区四区| 亚洲热线99精品视频| 无码人妻丰满熟妇精品| 亚洲精品国久久99热| 欧美一区二区三区爽爽爽| 亚洲日韩欧美一区二区在线| 中国一级片在线观看| 亚洲久本草在线中文字幕| 四虎免费在线视频| 亚洲一区二区偷拍精品| 一区二区三区免费高清视频| 亚洲国产精品一区二区www在线| 999久久久国产| 99精品欧美一区二区三区小说| 婷婷中文字幕在线观看| 国产精品一区免费在线观看| 九色porny91| 免费高清成人在线| 国产在线视频三区| bt7086福利一区国产| 日本黄色网址大全| 成人91在线观看| aaaaa一级片| 99免费精品视频| 国产免费看av| 中文字幕一区在线观看视频| 日韩一区二区a片免费观看| 国产精品人妖ts系列视频| 免费三级在线观看| 香蕉成人啪国产精品视频综合网 | 神马久久久久久久久久| 亚洲欧美激情一区| 黄色网址在线免费观看| 久久久伊人欧美| 素人啪啪色综合| 欧美在线视频导航| 涩涩av在线| 国产欧美精品日韩| 成人知道污网站| 欧洲精品在线一区| 日韩在线观看中文字幕| 久久青青草综合| 99re6这里只有精品| 亚洲午夜精品一区二区三区| 欧美国产免费| 久久久久久久久久久免费视频| av一区二区在线播放| 欧美少妇一级片| 羞羞答答国产精品www一本| 超碰人人草人人| 91原创在线视频| 欧产日产国产v| 91福利在线导航| 黄色三级网站在线观看| 亚洲午夜小视频| 多野结衣av一区| 日韩av成人在线| 91精品啪在线观看国产手机| 亚洲精品高清视频| 亚洲一区日韩在线| 久久久福利影院| 国产女同互慰高潮91漫画| 国产亚洲第一页| 欧美日韩精品欧美日韩精品一| 中文字幕在线播放av| 亚洲国产日韩精品在线| 久操视频在线免费播放| 国产91在线播放| 欧美大奶一区二区| 成人小视频在线观看免费| 免费国产亚洲视频| 精品国产午夜福利在线观看| 国产a级毛片一区| 国产白丝一区二区三区| 日本一区二区三区在线观看| 在线视频这里只有精品| 亚洲蜜桃精久久久久久久| 豆国产97在线 | 亚洲| 大伊人狠狠躁夜夜躁av一区| 中文在线字幕免费观| 日韩av在线免费观看| 欧美xxxx免费虐| 91免费欧美精品| 手机亚洲手机国产手机日韩| 国产一级特黄a大片免费| 2022国产精品视频| 五月婷婷中文字幕| 亚洲娇小xxxx欧美娇小| 18aaaa精品欧美大片h| 国产传媒一区| 精品二区久久| 无码国产69精品久久久久网站| 国产亚洲短视频| 亚洲无码精品一区二区三区| 亚洲欧美国产精品| 午夜成年人在线免费视频| 91沈先生作品| 欧美一区91| 人妻激情偷乱视频一区二区三区| 久久女同性恋中文字幕| 91精品一区二区三区蜜桃| 疯狂做受xxxx欧美肥白少妇 | 91社区在线高清| 国产精品日韩久久久久| 欧美日韩中文字幕一区二区三区| 日韩欧美猛交xxxxx无码| 日韩av在线发布| 国产三级在线观看完整版| 欧美午夜影院一区| 日韩专区在线| 3d动漫啪啪精品一区二区免费| 在线日韩网站| 黄色三级视频在线| 中文字幕欧美一区| 国产精品白浆一区二小说| 欧美性大战久久| 欧美三级电影一区二区三区| 91系列在线观看| 国内自拍一区| 久久久久xxxx| 国产亚洲精品中文字幕| 亚洲视频久久久| 欧美国产日韩在线| 私拍精品福利视频在线一区| 亚洲视频在线观看一区二区三区| 97久久精品人人做人人爽| 久艹视频在线观看| 亚洲国产又黄又爽女人高潮的| 在线不卡日本v二区707| 国产精品伊人日日| 首页国产欧美日韩丝袜| 亚洲精品自拍视频在线观看| 在线看日本不卡| yellow91字幕网在线| 精品亚洲欧美日韩| 伊人久久大香线蕉综合热线| 97公开免费视频| 亚洲女女做受ⅹxx高潮| 五月天福利视频| 国产日韩欧美综合| 久久国产成人午夜av影院宅| 伊人影院在线观看视频| 色综合久久综合网欧美综合网| 你懂的视频在线播放| 91久久精品美女高潮| 亚洲少妇诱惑| 小泽玛利亚一区二区免费|