### 彪哥

爱好前端

- 初识 TypeScript

- TypeScript 常用语法

- ts-axios 项目初始化

- ts-axios 基础功能实现

  - 处理请求 url 参数
  - 处理请求 body 数据
  - 处理请求 header
    - 需求分析
    - processHeaders 函数实现
    - 实现请求 header 处理逻辑
    - demo 编写
  - 获取响应数据
  - 处理响应 header
  - 处理响应 data

- ts-axios 异常情况处理

- ts-axios 接口扩展

- ts-axios 拦截器实现

- ts-axios 配置化实现

- ts-axios 取消功能实现

- ts-axios 更多功能实现

- ts-axios 单元测试

- ts-axios 部署与发布

- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现

HuangYi
2020-01-05
目录

# 处理请求 header

# # 处理请求 header

## # 需求分析

我们上节课遗留了一个问题：

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

1
2
3
4
5
6
7
8

我们做了请求数据的处理，把 `data` 转换成了 JSON 字符串，但是数据发送到服务端的时候，服务端并不能正常解析我们发送的数据，因为我们并没有给请求 `header` 设置正确的 `Content-Type`。

所以首先我们要支持发送请求的时候，可以支持配置 `headers` 属性，如下：

    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` 属性，需要自动设置请求 `header` 的 `Content-Type` 字段为：`application/json;charset=utf-8`。

## # processHeaders 函数实现

根据需求分析，我们要实现一个工具函数，对 request 中的 `headers` 做一层加工。我们在 `helpers` 目录新建 `headers.ts` 文件。

`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
24

这里有个需要注意的点，因为请求 `header` 属性是大小写不敏感的，比如我们之前的例子传入 `header` 的属性名 `content-type` 就是全小写的，所以我们先要把一些 `header` 属性名规范化。

## # 实现请求 header 处理逻辑

在这之前，我们先修改一下 `AxiosRequestConfig` 接口类型的定义，添加 `headers` 这个可选属性：

`types/index.ts`

    export interface AxiosRequestConfig {
      url: string
      method?: Method
      data?: any
      params?: any
      headers?: any
    }

1
2
3
4
5
6
7

`index.ts`：

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

    function transformHeaders (config: AxiosRequestConfig) {
      const { headers = {}, data } = config
      return processHeaders(headers, data)
    }

1
2
3
4
5
6
7
8
9
10

因为我们处理 `header` 的时候依赖了 `data`，所以要在处理请求 `body` 数据之前处理请求 `header`。

`xhr.ts`：

    export default function xhr (config: AxiosRequestConfig): void {
      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

这里要额外判断一个逻辑，当我们传入的 `data` 为空的时候，请求 `header` 配置 `Content-Type` 是没有意义的，于是我们把它删除。

## # demo 编写

    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
29

通过 demo 我们可以看到，当我们请求的数据是普通对象并且没有配置 `headers` 的时候，会自动为其添加 `Content-Type:application/json;charset=utf-8`；同时我们发现当 data 是某些类型如 `URLSearchParams` 的时候，浏览器会自动为请求 `header`加上合适的 `Content-Type`。

至此我们对于请求的处理逻辑暂时告一段落。目前我们的请求从网络层面是可以收到服务端的响应的，下一节课我们就从代码层面来处理服务端响应，并且让调用方可以拿到从服务端返回的数据。

编辑
(opens new window)
#TypeScript
上次更新: 2022/12/14, 19:36:42
处理请求 body 数据
获取响应数据

← 处理请求 body 数据 获取响应数据→

最近更新

  01
Git修改分支名
08-11

  02
CSS给table的tbody添加滚动条
06-29

  03
我做了一个手写春联小网页，祝大家虎年暴富 原创
01-28

更多文章>

Copyright © 2016-2022 Hesb | MIT License

- 跟随系统
- 浅色模式
- 深色模式
- 阅读模式