使用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 部分我們可以觀察發出的請求以及請求的參數。

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM