目录

🌒 实现处理请求 head

# 需求分析

要支持发送请求的数据类型,需要支持配置 headers 的属性来调整 content-type 。如下:

axios({
  method: 'post',
  url: '/base/post',
  headers: {
    'content-type': 'application/json;charset=utf-8'
  },
  data: {
    a: 1,
    b: 2
  }
})
1
2
3
4
5
6
7
8
9
10
11

并且在当传入的 data 为普通对象的时候, headers 如果没有配置 Content-Type 属性,需要自动设置请求 headerContent-Type 字段为: application/json;charset=utf-8

# processHeader 函数实现

创建文件 src/helpers/headers.ts 实现处理请求头工具函数:

import { isPlainObject } from './util'

function normalizeHeaderName(headers: any, normalizedName: string): void {
  if (!headers) return

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

export function processHeaders(headers: any, data: any): any {
  normalizeHeaderName(headers, 'Content-Type')

  if (isPlainObject(data)) {
    if (headers && !headers['Content-Type']) {
      headers['Content-Type'] = 'application/json;charset=utf-8'
    }
  }
  return headers
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

由于 header 属性的 key 是大小写不 in 干的,例如之前穿入的 header 属性名 content-type 是全小写的,所以要先把 header 属性名先处理规范化。

然后在添加 header

# 在入口文件添加请求 header 处理逻辑

首先需要先修改 AxiosRequstConfig 接口类型的定义,要添加 headers 可选属性:

src/types/index.ts

export interface AxiosRequestConfig {
  url: string
  method?: Method
  data?: any
  params?: any
  headers?: any
}
1
2
3
4
5
6
7

src/index.ts 中添加处理 header 逻辑:

function processConfig(config: AxiosRequestConfig): void {
  config.url = transformURL(config)
  config.headers = transformRequestHeader(config)
  config.data = transformRequestData(config)
}

// ... 

function transformRequestHeader(config: AxiosRequestConfig): any {
  const { headers = {}, data } = config
  return processHeaders(headers, data)
}
1
2
3
4
5
6
7
8
9
10
11
12

注意,因为处理 header 时,依赖了 data ,所以处理请求 body 数据之前处理请求 header

src/xhr.ts

import { AxiosRequestConfig } from './types'

export default function xhr(config: AxiosRequestConfig) {
  const { data = null, url, method = 'get', headers } = config

  const request = new XMLHttpRequest()

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

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

  request.send(data)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在使用 XMLHttpRequest 的实例时,添加额外的判断传入 data 为空的时候,请求 header 配置 Content-Type 是没有意义的,所以将它删除。

# 编写测试 DEMO

在上一节处理 body 参数的基础上,添加 headerscontent-type 类型:

axios({
  method: 'post',
  url: '/base/post',
  data: {
    a: 1,
    b: 2
  }
})

axios({
  method: 'post',
  url: '/base/post',
  headers: {
    'content-type': 'application/json'
  },
  data: {
    a: 1,
    b: 2
  }
})

const paramsString = 'q=URLUtils.searchParams&topic=api'
const searchParams = new URLSearchParams(paramsString)
axios({
  method: 'post',
  url: '/base/post',
  data: searchParams
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

测试可以看到,没有添加 headerscontent-type ,检测到请求数据是普通数据也会为其添加;同时当 data 为某些类型如 URLSearchParams 时,浏览器会自动为请求 header 添加合适的 Content-Type

📢 上次更新: 2022/09/02, 10:18:16