使用Typescript重构axios(三)——实现基础功能:处理get请求url参数

0. 系列文章

1.使用Typescript重构axios(一)——写在最前面
2.使用Typescript重构axios(二)——项目起手,跑通流程
3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数
4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数
5.使用Typescript重构axios(五)——实现基础功能:处理请求的header
6.使用Typescript重构axios(六)——实现基础功能:获取响应数据
7.使用Typescript重构axios(七)——实现基础功能:处理响应header
8.使用Typescript重构axios(八)——实现基础功能:处理响应data
9.使用Typescript重构axios(九)——异常处理:基础版
10.使用Typescript重构axios(十)——异常处理:增强版
11.使用Typescript重构axios(十一)——接口扩展
12.使用Typescript重构axios(十二)——增加参数
13.使用Typescript重构axios(十三)——让响应数据支持泛型
14.使用Typescript重构axios(十四)——实现拦截器
15.使用Typescript重构axios(十五)——默认配置
16.使用Typescript重构axios(十六)——请求和响应数据配置化
17.使用Typescript重构axios(十七)——增加axios.create
18.使用Typescript重构axios(十八)——请求取消功能:总体思路
19.使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式
20.使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式
21.使用Typescript重构axios(二十一)——请求取消功能:添加axios.isCancel接口
22.使用Typescript重构axios(二十二)——请求取消功能:收尾
23.使用Typescript重构axios(二十三)——添加withCredentials属性
24.使用Typescript重构axios(二十四)——防御XSRF攻击
25.使用Typescript重构axios(二十五)——文件上传下载进度监控
26.使用Typescript重构axios(二十六)——添加HTTP授权auth属性
27.使用Typescript重构axios(二十七)——添加请求状态码合法性校验
28.使用Typescript重构axios(二十八)——自定义序列化请求参数
29.使用Typescript重构axios(二十九)——添加baseURL
30.使用Typescript重构axios(三十)——添加axios.getUri方法
31.使用Typescript重构axios(三十一)——添加axios.all和axios.spread方法
32.使用Typescript重构axios(三十二)——写在最后面(总结)

项目源码请猛戳这里!!!

项目源码请猛戳这里!!!

1. 前言

在上篇文章中,我们仅仅实现了最基础的发送请求功能,但是发送get请求时携带的参数我们并没有进行处理,发出的请求参数也没有拼接到url上,那么本篇文章我们就来解决这个问题——处理get请求时的url参数。

2. 需求分析

首先,我们先来看下axios官方对get请求中所携带的参数是如何处理的。

2.1 普通参数

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

最终请求的 url/api/handleRequestURL/get?a=1&b=2

2.2 参数值为数组

axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: ['bar', 'baz']
  }
})

最终请求的 url/api/handleRequestURL/get?foo[]=bar&foo[]=baz

2.3 参数值为对象

axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: {
      bar: 'baz'
    }
  }
})

最终请求的 url/api/handleRequestURL/get?foo=%7B%22bar%22:%22baz%22%7D,foo 后面拼接的是 {"bar":"baz"}encode 后的结果。

2.4 参数值为 Date 类型

const date = new Date()

axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    date
  }
})

最终请求的 url/api/handleRequestURL/get?date=2019-07-24T04:46:41.05190Z

2.5 参数值包含特殊字符

axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: '@:$, '
  }
})

最终请求的 url/api/handleRequestURL/get?foo=@:$+,注意,空格 ` 会被转换成+`。

2.6 参数值包含null或undefined

axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: 'bar',
    baz: null
  }
})

最终请求的 url/api/handleRequestURL/get?foo=bar,对于值为 null 或者 undefined 的属性,会被丢弃。

2.7 url 中存在哈希#标记

axios({
  method: 'get',
  url: '/api/handleRequestURL/get#hash?bar=baz',
  params: {
    foo: 'bar'
  }
})

最终请求的 url/api/handleRequestURL/get,当原始url中存在哈希标记(#)时,所携带的所有参数params会被忽略,并且请求的url不包含#之后的东西。

2.8 url 中已存在的参数

axios({
  method: 'get',
  url: '/api/handleRequestURL/get?foo=bar',
  params: {
    bar: 'baz'
  }
})

最终请求的 url/api/handleRequestURL/get?foo=bar&bar=baz,会把携带的参数拼接到已存在参数的后面。

3. 实现buildURL 函数

根据上面分析,我们需要实现一个工具函数,将各种情况的 params 进行处理并且拼接到原始 url 上。于是我们在src目录下创建 helpers 文件夹,在这个文件夹下创建 url.ts 文件,未来会把处理 url 相关的工具函数都放在该文件中。

// src/helpers/url.ts

import {isDate, isObject} from './util'

function encode(val: string): string {
  return encodeURIComponent(val)
    .replace(/%40/g, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/g, '$')
    .replace(/%2C/gi, ',')
    .replace(/%20/g, '+')
    .replace(/%5B/gi, '[')
    .replace(/%5D/gi, ']')
}

export function bulidURL(url: string, params?: any) {
  // 如果params为空,直接返回原始url
  if (!params) {
    return url
  }

  // 如果url中有哈希标记,则直接返回原始url
  if (url.includes('#')) {
    const markIndex = url.indexOf('#')
    url = url.slice(0, markIndex)
    return url
  }
  // 定义键值对数组,用于最后拼接url,将params中的键值对进行处理最终放入parts中,
  // parts最后应该为['key=value','a=1','b=2','c=3',...]
  const parts: string[] = []

  // 遍历params中的键值对
  Object.keys(params).forEach((key) => {
    let val = params[key]
    // 如果有为null或undefined的值,不处理直接跳出循环
    if (val === null || typeof val === 'undefined') {
      return
    }
    let values: string[]
    // 如果值为数组,则将该值赋给临时数组变量values,用于下面遍历处理
    if (Array.isArray(val)) {
      values = val
      key += '[]'
    } else {
      // 如果值不是数组,则强行将其变为数组进行处理
      values = [val]
    }
    values.forEach((val) => {
      if (isDate(val)) {
        val = val.toISOString()
      } else if (isObject(val)) {
        val = JSON.stringify(val)
      }
      parts.push(`${encode(key)}=${encode(val)}`)
    })
  })

  // 将parts用'&'拼接
  let serializedParams = parts.join('&')

  if (serializedParams) {
    // 判断原始url中是否有已存在的参数,即判断是否有'?',
    // 如果有,则将处理后的键值对加'&'拼接在后面,
    // 如果没有,则将处理后的键值对加'?'拼接在后面
    url += (url.includes('?') ? '&' : '?') + serializedParams
  }

  return url
}

helpers文件夹下创建util.ts,将一些更为通用的工具函数,例如类型判断等放入该文件内。

// src/helpers/util.ts

const toString = Object.prototype.toString

export function isDate (val: any): val is Date {
  return toString.call(val) === '[object Date]'
}

export function isObject (val: any): val is Object {
  return toString.call(val) === '[object Object]'
}

4. 利用buildURL处理原始url

我们已经实现了 buildURL 函数,接下来我们来利用它实现 url 参数的处理逻辑。

index.ts 文件中添加如下代码:

// src/index.ts
import {AxiosRequestConfig} from './types'
import xhr from './xhr'
import {bulidURL} from "./helpers/url";

function axios(config: AxiosRequestConfig): void {
  processConfig(config)
  xhr(config)
}

function processConfig(config: AxiosRequestConfig): void {
  config.url = transformUrl(config)
}

function transformUrl(config: AxiosRequestConfig): string {
  const {url, params} = config
  return bulidURL(url, params);
}

export default axios

在执行 xhr 函数前,我们先执行 processConfig 方法,对 config 中的数据做处理,除了对 urlparams 处理之外,未来还会处理其它属性。

processConfig 函数内部,我们通过执行 transformUrl 函数修改了 config.url,该函数内部调用了 buildURL

OK,我们对 url 参数处理逻辑就实现完了,接下来我们编写 demo 来试试效果怎么样。

5. 编写demo

examples 目录下创建 handleRequestURL目录,在 handleRequestURL 目录下创建 index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>handleRequestURL demo</title>
</head>
<body>
<script src="/__build__/handleRequestURL.js"></script>
</body>
</html>

接着创建 app.ts 作为入口文件:

// examples/handleRequestURL/app.ts

import axios from '../../src/index'

// 普通参数
axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    a: 1,
    b: 2
  }
})

// 参数值为数组
axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: ['bar', 'baz']
  }
})

// 参数值为对象
axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: {
      bar: 'baz'
    }
  }
})

// 参数值为 Date 类型
const date = new Date()
axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    date
  }
})

// 参数值包含特殊字符
axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: '@:$, '
  }
})

// 参数值包含null或`undefined`
axios({
  method: 'get',
  url: '/api/handleRequestURL/get',
  params: {
    foo: 'bar',
    baz: null
  }
})

// url 中存在哈希#标记
axios({
  method: 'get',
  url: '/api/handleRequestURL/get#hash?bar=baz',
  params: {
    foo: 'bar'
  }
})

// url 中已存在的参数
axios({
  method: 'get',
  url: '/api/handleRequestURL/get?foo=bar',
  params: {
    bar: 'baz'
  }
})

接着在 server/server.js 添加新的接口路由:

router.get('/api/handleRequestURL/get', function(req, res) {
  res.json(req.query)
})

最后在根目录下的index.html中加上启动该demo的入口:

<li><a href="examples/handleRequestURL">handleRequestURL</a></li>

OK,我们在命令行中执行:

# 同时开启客户端和服务端
npm run server | npm start

接着我们打开 chrome 浏览器,访问 http://localhost:8000/ 即可访问我们的 demo 了,我们点击 handleRequestURL ,通过F12network 部分我们可以观察发出的请求以及请求的参数。

(完)

原文地址:https://www.cnblogs.com/wangjiachen666/p/11237521.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我最大的一个关于TypeScript的问题是,它将原型的所有方法(无论访问修饰符)编译.例classExample{publicgetString():string{return"HelloWorld";}privategetNumber():number{return123;}}众所周知,访问修饰符仅在编译时检
我对React很新,我正在尝试理解子组件之间相互通信的简洁方法.在一个简单的组件中,我知道我可以使用props将数据传递给子节点,并让子节点的回调将数据传递回父组件.在稍微复杂的情况下,当我在父组件中有多个子组件时,子组件之间的通信会有点混乱.我不确定我应该为同级别的儿童组
我有一个非常简单的表单,我将用户电子邮件存储在组件的状态,并使用onChange函数更新状态.有一个奇怪的事情发生在我的onChange函数用函数更新状态时,我在键入时在控制台中得到两个错误.但是,如果我使用对象更新状态,则不会出现错误.我相信用函数更新是推荐的方法,所以我很想知道为
我发现接口非常有用,但由于内存问题我需要开始优化我的应用程序,我意识到我并不真正了解它们在内部如何工作.说我有interfaceFoo{bar:number}我用这种类型实例化一些变量:letx:Foo={bar:2}Q1:这会创建一个新对象吗?现在,假设我想改变bar的值.我这样做有两种
我得到了一个json响应并将其存储在mongodb中,但是我不需要的字段也进入了数据库,无论如何要剥离不道德的字段?interfaceTest{name:string};consttemp:Test=JSON.parse('{"name":"someName","age":20}')asTest;console.log(temp);输出:{name:'someName
我试图使用loadsh从以下数组中获取唯一类别,[{"listingId":"p106a904a-b8c6-4d2d-a364-0d21e3505010","section":"section1","category":"VIPPASS","type":"paper","availableTi
我有以下测试用例:it("shouldpassthetest",asyncfunction(done){awaitasyncFunction();true.should.eq(true);done();});运行它断言:Error:Resolutionmethodisoverspecified.SpecifyacallbackorreturnaPromise;n
我正在一个有角度的2cli项目中工作,我必须创建一个插件的定义,因为它不存在它的类型.这个插件取决于已经自己输入的主库,它可以工作.无论如何,我有两个文件主要的一个图书馆类型文件AexportclassAextendsB{constructor(...);methodX():void;}我需要为我的
我有三元操作的问题:leta=undefined?"Defined!":"DefinitelyUndefined",b=abc?"Defined!":"DefinitelyUndefined",//ReferenceErrorc=(abc!==undefined)?"Defined!":"DefinitelyUndefin
下面的代码片段是30秒的代码网站.这是一个初学者的例子,令人尴尬地让我难过.为什么这样:constcurrentURL=()=>window.location.href;什么时候可以这样做?constcurrentURL=window.location.href;解决方法:第一个将currentURL设置为一个求值为window.location.href的
我是TypeScript和AngularJS的新手,我正在尝试从我的API转换日期,例如:"8/22/2015"…到ISO日期.将日期正确反序列化为Date类型的TypeScript属性.但是,当我尝试以下命令时(在typescript中,this.dateDisplay的类型为string)this.dateDisplay=formats.dateTimeValue.toISOString
我的名为myEmployees的数组中有5个名字,但是当我运行代码时,它只打印出其中的3个.我相信这种情况正在发生,因为脚本中的for循环覆盖了它在HTML文档中编写的前一行.我怎样才能解决这个问题?YearlyBulletinBoardAnnouncements!CongratulationstoTaylor,youhavebeenheref
我看到有一种方法可以在摩纳哥编辑器中设置scrolltop.如何滚动到特定行而不是特定像素?解决方法:如在文档中:https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.icodeeditor.html滚动到顶部,在px中:editor.setScrollPosition({scrollTop:0});滚动到特定
在从同一个类继承的一个数组中收集各种不同的对象时,如何在TypeScript中设置一个优等的类,以便TypeScript不显示错误?我正在尝试这样:interfaceIVehicle{modelName:string}interfaceICarextendsIVehicle{numberOfDoors:number,isDropTop:boolean}inte
什么是TypescriptTypeScript是一种由微软开发的自由和开源的编程语言,它是JavaScript的一个超集,扩展了JavaScript的语法。作者是安德斯大爷,Delphi、C#之父(你大爷永远是你大爷)。把弱类型语言改成了强类型语言,拥有了静态类型安全检查,IDE智能提示和追踪,代码重构简单、可读性
0.系列文章1.使用Typescript重构axios(一)——写在最前面2.使用Typescript重构axios(二)——项目起手,跑通流程3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数5.使用Typescript重构axios(五
1.1Typescript介绍1.TypeScript是由微软开发的一款开源的编程语言,像后端java、C#这样的面向对象语言可以让js开发大型企业项目。2.TypeScript是Javascript的超级,遵循最新的ES6、Es5规范(相当于包含了es6、es5的语法)。TypeScript扩展了JavaScript的语法。3.最新的Vu
0.系列文章1.使用Typescript重构axios(一)——写在最前面2.使用Typescript重构axios(二)——项目起手,跑通流程3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数5.使用Typescript重构axios(
webpack.config.jsconstpath=require('path');constCopyWebpackPlugin=require('copy-webpack-plugin');constExtractTextPlugin=require('extract-text-webpack-plugin');const{CleanWebpackPlugin}=require('clean-webpac
我在这篇ECMAScriptpage上读到“class”是JavaScript的一部分.在这个关于TypeScript的页面上,我看到’class’也可以在Typescript中找到.我的问题是,开发未来JavaScript应用程序的正确方法是利用(a)JavaScript中的面向对象功能以及EMACScript7.0中可用的功能或(b)使用TypeScript