手把手带你使用 typescript 实现一个 axios 库(二)url 参数处理

1,385 阅读1分钟

主要内容:对 get 请求参数的处理

需求分析

看下面这个请求

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

系列一实现了axios的基本请求,但是如果你细心会发现还存在问题,就是我们的请求url其实是不全的。具体看下图

图片占位

可以看到我们并没有将params的参数拼接到url尾部,so 我们这一节要做的事情就是完善 url。

axios中参数params可以有多重,如下所示

// 为数组
axios({
  method: 'get',
  url: '/base/get',
  params: {
    foo: ['aaa', 'bbb']
  }
})
// url: /base/get?foo[]=aaa&foo[]=bbb

// 为对象
axios({
  method: 'get',
  url: '/base/get',
  params: {
    foo: {
      bar: 'baz'
    }
  }
})
// url: /base/get?foo=%7B%22bar%22:%22baz%22%7D, foo 后面拼接的是 {"bar":"baz"} encode 后的结果

// 为日期
const date = new Date()

axios({
  method: 'get',
  url: '/base/get',
  params: {
    date
  }
})
// url: /base/get?date=2019-04-01T05:55:39.030Z, date 后面拼接的是 date.toISOString() 的结果
// 特殊字符等。字符:@ : $ , [ ] 是允许出现在url参数中的
axios({
  method: 'get',
  url: '/base/get',
  params: {
    foo: '@:$, '
  }
})
// url: /base/get?foo=@:$+, 注意,我们会把空格 转换成 +

此章节只展示params数组时的实现,其余的可以自己对照源码进行查看

思路分析

先看下列请求,接下来的代码都是以这个请求为例进行说明。

axios({
  method: 'get',
  url: '/base/get',
  params: {
    foo: ['aaa', 'bbb']
  }
})

我们最终要的结果为/base/get?foo[]=aaa&foo[]=bbb,大体实现步骤为以下几步。

  • 1、1、创建一个数组,用于存放键值对,其最终结构为[ 'foo[]=aaa', 'foo[]=bbb' ]
  • 2、循环params,获取其键值对进行操作
  • 3、创建一个临时数组,用于存放处理好的params,结构为[ 'aaa', 'bbb' ]
  • 4、4、循环添加,以key=value的形式,
  • 5、字符串拼接

实现

接下来我们来看具体实现

demo.js

let url = '/base/get'
let params = {
  foo: ['aaa', 'bbb']
}
// 1、创建一个数组,用于存放键值对,其最终结构为[ 'foo[]=aaa', 'foo[]=bbb' ]
const parts = []
// 2、循环params,获取其键值对进行操作
Object.keys(params).forEach(key => {
  let val = params[key] // val: ['aaa', 'bbb'] xiaofeng, key:foo too

  // 3、创建一个临时数组,用于存放处理好的params,结构为[ 'aaa', 'bbb' ]
  let values = []

  if (Array.isArray(val)) {
    values = val
    key += '[]'
  } else {
    values = [val]
  }

  // 4、循环添加,以key=value的形式,
  values.forEach(item => {
    parts.push(`${key}=${item}`)
  })
  // parts: [ 'foo[]=aaa', 'foo[]=bbb' ]
})
let serializedParams = parts.join('&')
// 5、字符串拼接
url += `${url}?${serializedParams}`
console.log(url) // 输出:/base/get/base/get?foo[]=aaa&foo[]=bbb

这里用原生 js 粗略的实现了这个功能。

接下来我们用typescript来进行改写

buildURL 函数实现

遵循模块化的思想,我们也将这个功能拆分出来,成为一个单独的模块。 src下新建一个helpers目录用于存放工具函数和辅助方法,在这个目录下新建一个url.ts文件用于存放url相关的工具函数。

根据上面的代码,你不难写出如下代码

export function buildURL(url: string, params?: any): string {
  if (!params) {
    return url
  }
  // 这里的写法可以参考typescript文档https://www.tslang.cn/docs/handbook/basic-types.html
  const parts: string[] = []
  Object.keys(params).forEach(key => {
    const val = params[key]

    if (val === null || typeof val === 'undefined') {
      return
    }

    let values = []
    if (Array.isArray(val)) {
      values = val
      key += '[]'
    } else {
      values = [val]
    }

    values.forEach(item => {
      //
      parts.push(`${key}=${item}`)
    })
  })

  let serializedParams = parts.join('&')

  url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams

  return url
}

此时我们就用 typescript 实现了对url参数为数组时的处理,不过我们这里还有很多需要完善的地方,接下来我带领你一步一步的去完善,修改它。

为完待续...

换工作的原因这个暂时没时间更新了。等忙过这一段时间