处理 params

params参数value为以下类型需要处理:

  1. 数组 key 需要加上[]
  2. 对象 JSON.stringfy()
  3. 日期Date类型
  4. 特殊字符, 如空格等…
  5. 空值忽略
  6. url中hash标记
  7. 保留url已经存在的参数 ```typescript import { isDate, isObject, encode } from “./util”

export function buildRUL(url: string, params?: any): string { if (!params) { return url }

const parts: string[] = [] Object.keys(params).forEach(key => { const value = params[key] if (value === undefined || value === null) { return } // 统一处理为数组 let values = [] if (Array.isArray(value)) { key += ‘[]’ values = value } else { values = [value] } // 拼接参数 values.forEach(val => { if (isDate(val)) { val = (val as Date).toISOString() } if (isObject(val)) { val = JSON.stringify((val as Object)) } parts.push(${encode(key)}=${encode(val)}) }) })

let serializedParams = parts.join(‘&’) if (serializedParams) { // 去掉锚点# (对于后端没有用) const markIndex = url.indexOf(‘#’) if (markIndex !== -1) { url = url.slice(0, markIndex) } // 如果有? 继续拼接&,否则加上 ? url += url.indexOf(‘?’) !== -1 ? &${serializedParams} : ?${serializedParams} } return url }

  1. <a name="fa0b6665"></a>
  2. ## 处理 data
  3. <a name="1bc972b5"></a>
  4. ### 表单数据提交常见格式
  5. 1. 默认 application/x-www-form-urlencoded
  6. 1. multipart/form-data,不对字符编码。在使用包含文件上传控件的表单时,必须使用该值
  7. <a name="22fd4789"></a>
  8. ### Content-Type 定义提交数据类型
  9. 1. json 格式字符串:application/json
  10. 1. 默认 application/x-www-form-urlencoded
  11. 1. 文件上传:multipart/form-data
  12. <a name="301aa4f6"></a>
  13. ### 转换 data 数据
  14. 1. 如果数据为普通对象,转成 json 格式字符串,
  15. 1. 请求头需要把content-type: application/json
  16. ```typescript
  17. export function transformRequest(data: any) {
  18. if (isPlainObject(data)) {
  19. return JSON.stringify(data)
  20. }
  21. return data
  22. }

处理 headers

  1. 如果传入为普通对象,设置 Content-Type 为 application/json
  2. 定义函数 normalizeName,处理传入 headeres 的 key 大小写问题 ```typescript import { isPlainObject } from “./util”;

// 处理headername 大小写问题 function normalizeHeaderName(headers: any, normalizeName: string) { if (!headers) { return }

Object.keys(headers).forEach(name => { if (name !== normalizeName && name.toUpperCase() === normalizeName.toUpperCase()) { headers[normalizeName] = headers[name] delete headers[name] } }) }

export function processHeaders(headers: any = {}, data: any) { normalizeHeaderName(headers, ‘Content-type’)

if (isPlainObject(data) && !headers[‘Content-Type’]) { headers[‘Content-Type’] = ‘application/json’ }

return headers }

  1. <a name="9bfb9bcb"></a>
  2. ## 处理 Response
  3. <a name="drBt3"></a>
  4. ### 响应头headers
  5. 通过`request.getAllResponseHeaders()`获取的headers数据:

connection: keep-alive content-length: 66 content-type: application/json; charset=utf-8 date: Mon, 23 May 2022 16:45:28 GMT etag: W/“42-B3q+nueBZBTNpq/cPd3/uIemlRo” keep-alive: timeout=5 x-powered-by: Express

  1. 把以上数据处理为一个对象
  2. ```typescript
  3. // 转换 responseHeaders
  4. export function parseHeaders(headers: string) {
  5. const headerOjb = Object.create(null)
  6. if (!headerOjb) {
  7. return headerOjb
  8. }
  9. // 通过换行符分割
  10. headers.split('\r\n').forEach(row => {
  11. const [key, value] = row.split(':')
  12. if (key) {
  13. headerOjb[key.trim().toLowerCase()] = (value || '').trim()
  14. }
  15. })
  16. return headerOjb
  17. }

响应数据 data

响应数据都试着转成json格式

export function transformResponse(data:any){
  if(typeof data === 'string'){
    try {
      data = JSON.stringify(data)
    } catch (error) {
      // 转换失败
    }
  }

  return data
}

响应结果合并

export interface AxiosResponse {
  headers: any,
  status: number
  data: any,
  config: AxiosRequestConfig,
  request: any,
}
import { parseHeaders } from './helpers/headers'
import { AxiosPromise, AxiosRequestConfig, AxiosResponse } from './types'

export default function xhr(config: AxiosRequestConfig): AxiosPromise {
  return new Promise((resolve, reject) => {
    const { url, method = 'get', data = null, headers, responseType } = config
    const request = new XMLHttpRequest()

    if (responseType) {
      request.responseType = responseType
    }

    request.open(method.toLowerCase(), url, true)

    // 设置请求头
    Object.keys(headers).forEach(name => {
      if (data === null && name.toLowerCase() === 'content-type') {
        delete headers[name]
      } else {
        request.setRequestHeader(name, headers[name])
      }
    })

    request.onreadystatechange = event => {
      if (request.readyState !== 4) {
        return
      }

      const responseData = responseType === 'text' ? request.responseText : request.response
      const response: AxiosResponse = {
        headers: parseHeaders(request.getAllResponseHeaders()),
        status: request.status,
        data: responseData,
        request: request,
        config
      }
      resolve(response)
    }
    request.onerror = err => {
      reject(err)
    }
    request.send(data)
  })
}