:::tips 简单实现一个类似axios的库 github npm :::

处理请求url参数

需求分析

参数值为数组

  1. easyFetch({
  2. url: 'test.json',
  3. method: 'get',
  4. params: {
  5. foo: ['bar', 'baz']
  6. }
  7. })

最终的url是test.json?foo[]=bar&foo[]=baz


参数值为对象

  1. easyFetch({
  2. url: 'test.json',
  3. method: 'get',
  4. params: {
  5. foo: {
  6. bar: 'baz'
  7. }
  8. }
  9. })

最终的url是test.json?foo=%7b22%baz,foo后面拼接的是{bar: 'baz'} encode的结果


参数值为Date类型

  1. const date = new Date()
  2. easyFetch({
  3. url: 'test.json',
  4. method: 'get',
  5. params: {
  6. date
  7. }
  8. })

最终的url是test.json?date=2020-11-24T05...,date后面拼接的是date.toISOString()的结果


空值忽略

  1. easyFetch({
  2. url: 'test.json',
  3. method: 'get',
  4. params: {
  5. foo: 'bar',
  6. baz: null
  7. }
  8. })

最终url是test.json?foo=bar

丢弃url中的哈希标记

  1. easyFetch({
  2. url: 'test.json#hash',
  3. method: 'get',
  4. params: {
  5. foo: 'bar'
  6. }
  7. })

最终url是test.json?foo=bar

保存已有的参数

  1. easyFetch({
  2. url: 'test.json?foo=bar',
  3. method: 'get',
  4. params: {
  5. bar: 'baz'
  6. }
  7. })

最终url是test.json?foo=bar&bar=baz

buildURL函数实现

  1. import {isDate, isObject} from './util'
  2. function encode(val: string): string {
  3. return encodeURIComponent(val)
  4. .replace(/%40/g, '@')
  5. .replace(/%3A/gi, ':')
  6. .replace(/%24/g, '$')
  7. .replace(/%2C/gi, ',')
  8. .replace(/%20/g, '+')
  9. .replace(/%5B/gi, '[')
  10. .replace(/%5D/gi, ']')
  11. }
  12. export function buildURL(url: string, params?: any): string {
  13. if(!params) return url
  14. const parts:string[] = []
  15. Object.keys(params).forEach(key => {
  16. const val = params[key]
  17. if(val === null || typeof val === 'undefined') return
  18. let values = []
  19. if(Array.isArray(val)) {
  20. values = val
  21. key += '[]'
  22. } else {
  23. values = [val]
  24. }
  25. values.forEach(val => {
  26. if(isDate(val)) {
  27. val = val.toISOString()
  28. } else if(isObject(val)) {
  29. val = JSON.stringify(val)
  30. }
  31. parts.push(`${encode(key)}=${encode(val)}`)
  32. })
  33. })
  34. let serializedParams = parts.join('&')
  35. if (serializedParams) {
  36. const markIndex = url.indexOf('#')
  37. if (markIndex !== -1) {
  38. url = url.slice(0, markIndex)
  39. }
  40. url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams
  41. }
  42. return url
  43. }

处理请求body数据

XMLHttpRequest.send() 方法接受一个可选的参数,其作为请求主体;如果请求方法是 GET 或者 HEAD,则应将请求主体设置为 null — MDN

  1. easyFetch({
  2. url: 'test.json',
  3. method: 'post',
  4. data: {
  5. a: 1,
  6. b: 2
  7. }
  8. })

如果是post请求,data是普通对象的话,需要通过JSON.stringify(data)转换成json字符串,符合XHR请求中要发送的数据体规范之一USVString 对象

处理headers

  1. easyFetch({
  2. url: 'test.json',
  3. method: 'post',
  4. headers: {
  5. 'content-type': 'application/json',
  6. 'Accept': 'application/json'
  7. },
  8. data: {
  9. a: 1,
  10. b: 2
  11. }
  12. })
  • 如果是post请求,data是普通对象的话,用户没有定义headers,自动添加{``'content-type': 'application/json;charset=utf-8'``}
  • 如果用户有定义,也要保留用户的headers