Fetch请求封装与Transform处理

Gary Chen
Fetch请求封装与Transform处理

Fetch请求封装与Transform处理

下面是一个完整的fetch请求封装,包含请求和响应的transform处理:

class HttpRequest {
  constructor(baseURL = '', timeout = 10000) {
    this.baseURL = baseURL;
    this.timeout = timeout;
  }

  /**
   * 请求拦截器(请求transform)
   * @param {Request} request - 请求对象
   * @returns {Request} 处理后的请求
   */
  requestInterceptor(request) {
    // 在这里可以添加全局请求头、认证token等
    request.headers.set('Content-Type', 'application/json');
    // request.headers.set('Authorization', `Bearer ${localStorage.getItem('token')}`);
    return request;
  }

  /**
   * 响应拦截器(响应transform)
   * @param {Response} response - 响应对象
   * @returns {Promise} 处理后的响应数据
   */
  async responseInterceptor(response) {
    // 检查HTTP状态码
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message || `HTTP error! status: ${response.status}`);
    }

    // 根据Content-Type处理不同响应类型
    const contentType = response.headers.get('content-type');
    if (contentType && contentType.includes('application/json')) {
      return response.json();
    } else if (contentType && contentType.includes('text/plain')) {
      return response.text();
    } else {
      return response.blob();
    }
  }

  /**
   * 发送请求
   * @param {string} url - 请求URL
   * @param {Object} options - 请求选项
   * @returns {Promise} 请求结果
   */
  async request(url, options = {}) {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);

    try {
      const fullUrl = this.baseURL + url;
      let request = new Request(fullUrl, {
        ...options,
        signal: controller.signal
      });

      // 请求transform
      request = this.requestInterceptor(request);

      const response = await fetch(request);
      
      // 响应transform
      const data = await this.responseInterceptor(response);
      
      return data;
    } catch (error) {
      if (error.name === 'AbortError') {
        throw new Error('请求超时');
      }
      throw error;
    } finally {
      clearTimeout(timeoutId);
    }
  }

  // 封装常用HTTP方法
  get(url, params = {}, options = {}) {
    const query = new URLSearchParams(params).toString();
    const fullUrl = query ? `${url}?${query}` : url;
    return this.request(fullUrl, {
      ...options,
      method: 'GET'
    });
  }

  post(url, body = {}, options = {}) {
    return this.request(url, {
      ...options,
      method: 'POST',
      body: JSON.stringify(body)
    });
  }

  put(url, body = {}, options = {}) {
    return this.request(url, {
      ...options,
      method: 'PUT',
      body: JSON.stringify(body)
    });
  }

  delete(url, options = {}) {
    return this.request(url, {
      ...options,
      method: 'DELETE'
    });
  }

  // 可以添加patch等其他方法
}

// 使用示例
const api = new HttpRequest('https://api.example.com');

// 发送GET请求
api.get('/users', { page: 1, limit: 10 })
  .then(data => console.log(data))
  .catch(error => console.error(error));

// 发送POST请求
api.post('/users', { name: 'John', age: 30 })
  .then(data => console.log(data))
  .catch(error => console.error(error));

主要特点

  1. 请求transform处理

    • 统一设置请求头(如Content-Type、Authorization)
    • 可以添加全局请求参数
    • 请求超时处理
  2. 响应transform处理

    • 统一错误处理(HTTP状态码非200-299时抛出错误)
    • 根据Content-Type自动解析响应数据(JSON/Text/Blob)
    • 可以添加统一的响应数据处理逻辑
  3. 其他功能

    • 支持常用HTTP方法(GET/POST/PUT/DELETE)
    • 支持请求参数自动序列化
    • 支持请求超时取消

扩展建议

  1. 可以添加请求/响应日志记录
  2. 可以添加请求重试机制
  3. 可以添加请求缓存功能
  4. 可以添加更完善的错误分类处理
  5. 可以添加请求取消功能(使用AbortController)

这个封装提供了良好的扩展性,你可以根据项目需求进一步定制transform逻辑。