qs.stringify()的疑问

来源:9-4 合并配置的设计与实现 - flatten headers + demo 编写

慕粉1470117225

2020-07-14

老师,qs.stringify()将对象序列化成URL的形式,然后content-type就会变成application/x-www-form-urlencoded,这是为啥啊

  // `data` 是作为请求主体被发送的数据
  // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: {
    firstName: 'Fred'
  },
写回答

2回答

许愿瓶啊

2020-08-21

这个是默认headers的配置,代码如下:

const methodsWithData = ['post', 'put', 'patch']

methodsWithData.forEach(method => {
  (defaults.headers as any)[method] = {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
})

注意这里是在 header 的 post 属性上挂载的,还有一个地方会定义 content-type,代码如下:

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

  if (isPlanObject(data)) {
    if (headers && !headers['Content-Type']) {
      headers['Content-Type'] = 'application/json;charset=utf-8'
    }
  }

  return headers
}

这里判断用户没有定义content-type,并且 data 是纯对象的话就会在 header 上挂载 content-type

最关键的合并策略代码如下:

export function flattenHeaders(headers: any, method: Method): any {
  if (!headers) {
    return
  }

  headers = deepMerge(headers.common, headers[method], headers)

  const methodsDelete = ['delete', 'get', 'head', 'options', 'post', 'put', 'patch', 'common']

  methodsDelete.forEach(method => {
    delete headers[method]
  })

  return headers
}

这里会有一个优先级的问题,deepMerge 的合并会依次遍历并挂载属性,所以属性相同的情况下后面的对象会覆盖前面对象的属性,这里的优先级关系是:

    直接挂载在 header 上的属性最牛!

    其次是各种方法定义的属性

    最后是公共属性

这样写也非常的合理,所以这里的 data 如果是纯对象的话会直接挂载在 headers 上,优先级最高,application/json;charset=utf-8
会覆盖了 post 属性上的 application/x-www-form-urlencoded,如果不是的话就会用默认的 application/x-www-form-urlencoded

0
0

ustbhuangyi

2020-07-14

你可以打个断点调试一下,在发送请求前,看看 request header 有哪些。

0
0

下一代前端开发语言 TypeScript从零重构axios

课程从零开始重构功能完整的JS库,是学习造轮子的不二之选!

2632 学习 · 877 问题

查看课程