使用TypeScript封装XMLHttpRequest

发表于: 2024-08-04 21:15:49

简介: 使用TypeScript对XMLHttpRequest进行封装,类似axios库

class HttpRequest {
  baseUrl = null
  interceptors = {
    request: [],
    response: [],
  }

  constructor(baseUrl = '') {
    this.baseUrl = baseUrl
    this.interceptors = {
      request: [],
      response: [],
    }
  }

  use(type, interceptor) {
    if (type === 'request' || type === 'response') {
      this.interceptors[type].push(interceptor)
    }
  }

  async get(url, params = {}, headers = {}) {
    return this._sendRequest('GET', url, params, headers)
  }

  async post(url, data = {}, headers = {}) {
    return this._sendRequest('POST', url, data, headers)
  }

  async put(url, data = {}, headers = {}) {
    return this._sendRequest('PUT', url, data, headers)
  }

  async delete(url, params = {}, headers = {}) {
    return this._sendRequest('DELETE', url, params, headers)
  }

  async _sendRequest(method, url, data = null, headers = {}) {
    let finalUrl = this.baseUrl + url
    const finalMethod = method.toUpperCase()
    let finalHeaders = { 'Content-Type': 'application/json', ...headers }
    let finalData = data

    // 应用请求拦截器
    for (const interceptor of this.interceptors.request) {
      const result = await interceptor({ method: finalMethod, url: finalUrl, data: finalData, headers: finalHeaders })
      finalUrl = result.url
      finalData = result.data
      finalHeaders = result.headers
    }

    if (finalMethod === 'GET' || finalMethod === 'DELETE') {
      const params = new URLSearchParams(finalData).toString()
      finalUrl += params ? `?${params}` : ''
      finalData = null
    }
    else {
      finalData = JSON.stringify(finalData)
    }

    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest()
      xhr.open(finalMethod, finalUrl, true)

      for (const key in finalHeaders) {
        if (Object.prototype.hasOwnProperty.call(finalHeaders, key)) {
          xhr.setRequestHeader(key, finalHeaders[key])
        }
      }

      xhr.onload = async () => { // 使用箭头函数来保持正确的 this 上下文
        let responseData
        try {
          responseData = JSON.parse(xhr.responseText)
        }
        catch (error) {
          responseData = xhr.responseText
        }

        let response = {
          data: responseData,
          status: xhr.status,
          statusText: xhr.statusText,
          headers: xhr.getAllResponseHeaders(),
        }

        // 应用响应拦截器
        for (const interceptor of this.interceptors.response) {
          try {
            response = await interceptor(response)
          }
          catch (error) {
            reject(error)
            return
          }
        }

        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(response.data)
        }
        else {
          reject(new Error(`HTTP error! status: ${xhr.status}`))
        }
      }

      xhr.onerror = () => { // 同样使用箭头函数
        reject(new Error('Network error occurred'))
      }

      xhr.send(finalData)
    })
  }
}

export default HttpRequest

最后更新于:2024-08-04 21:15:49