尝试一个基于fetch封装的现代请求库——ky 并进行二次封装

395 阅读4分钟

前言

这篇文章将对ky库进行简单的使用并进行一个基本的封装

ky简介

ky是一个基于fetchAPI封装的请求库,兼容浏览器和node,类似于axios,但是axios的实现是在浏览器端是基于XMLHttpRequests而在node端则是基于原生的http模块.

目前ky在github上有13.6k的Star,还是非常火的,不能总拘泥于常用的axios所以我决定试用一下ky

ky的github地址

简单试用

先随便开个Vue项目

安装ky

pnpm i ky

基本使用

<script setup lang="ts">
import ky from 'ky'

async function kyTest() {
  const res = await ky.get('http://localhost:3000/todo').json()
  console.log(res)
}
</script>

<template>
  <button @click="kyTest">
    请求测试
  </button>
</template>

3000端口开了一个我自己写的后端

这里可以看到请求的data直接被json()方法取出来了

image.png

ts类型

用ts的话此时的res类型是unknown 可以通过传泛型去定义

先定义一个类型

interface TodoType {
  code: number
  msg: string
  data: {
    id: string
    title: string
    isCheck: boolean
    time: string
  }
}

在原本的请求上修改一下

  const res = await ky.get<TodoType>('http://localhost:3000/todo').json()

 // 或者
 
   const res = await ky.get('http://localhost:3000/todo').json<TodoType>()
   
 // 或者
 
   const res = await ky<TodoType>('http://localhost:3000/todo', { method: 'GET' }).json()

简单封装

阅读文档可以得知ky支持类似于axioscreate方法.并且内置了几个hooks

这里在utils文件夹中开始封装

新建一个文件夹名为KY并新建index.ts

image.png

// index.ts
import ky from 'ky'

const KY = ky.create({})

export default KY

在项目中请求的地址一般会有一个环境变量

比如开发阶段会经常使用mock 测试和生产都会有单独的地址 所以使用vite的环境变量作为基请求地址

ky会自动重试,我们需要把它设置为0

import ky from 'ky'

const { VITE_APP_URL } = import.meta.env

const KY = ky.create({
  prefixUrl: VITE_APP_URL,
  retry: 0,
})

export default KY

需要注意的是封装之后请求不用再以/开头并且以/开头会报错

比如prefixUrl为http://localhost:3000则请求的时候只需要

await KY<TodoType>('todo', { method: 'GET' }).json()

即可

拦截器/钩子

ky提供了几种钩子

  • beforeRequest 请求发起之前调用钩子
  • beforeRetry 重试发起之前调用钩子
  • beforeError 请求抛出HTTPError之前调用的Hook 可以进行一些错误处理
  • afterResponse 请求响应之后调用的钩子 可以统一处理一下请求响应

使用也很简单

const KY = ky.create({
  prefixUrl: VITE_APP_URL,
  retry: 0,
  hooks: {
    beforeRequest: [
      (request: KyRequest) => {
        console.log(request)
      },
    ],
  },
})

但是我不想把方法都写在index里所以新建一个tool.ts文件

beforeRequest主要是用来加上token

const beforeRequest: BeforeRequestHook[] = [
  (request: KyRequest) => {
    // 获取token 这里模拟一下
    const token = 'xxxxx'
    if (token)
      request.headers.set('token', token)
  },
]

beforeError用来处理网络错误

const networkErrMap: { [key: string]: string } = {
  400: '错误的请求',
  401: '无权访问', // 拒绝访问
  403: '拒绝访问',
  404: '请求错误,未找到该资源',
  405: '请求方法未允许',
  408: '请求超时',
  500: '服务器端出错',
  501: '网络未实现',
  502: '网络错误',
  503: '服务不可用',
  504: '网络超时',
  505: 'http版本不支持该请求',
}

const beforeError: BeforeErrorHook[] = [
  (error: HTTPError<unknown>) => {
    const { status } = error.response
    // 可以用组件库的方法提示错误
    // 比如 ElMessage ElNotification
    console.log(networkErrMap[status] ?? '其他网络错误')
    return error
  },
]

afterResponse 主要是根据业务状态码进行处理,这里不再赘述了

最后

完整代码奉上

// index.ts
import ky from 'ky'
import { beforeError, beforeRequest } from './tool'

const { VITE_APP_URL } = import.meta.env

const KY = ky.create({
  prefixUrl: VITE_APP_URL,
  retry: 0,
  hooks: {
    beforeRequest,
    beforeError,
  },
})

export default KY
// tool.ts
import type { BeforeErrorHook, BeforeRequestHook, HTTPError, KyRequest } from 'ky'

const networkErrMap: { [key: string]: string } = {
  400: '错误的请求',
  401: '无权访问', // 拒绝访问
  403: '拒绝访问',
  404: '请求错误,未找到该资源',
  405: '请求方法未允许',
  408: '请求超时',
  500: '服务器端出错',
  501: '网络未实现',
  502: '网络错误',
  503: '服务不可用',
  504: '网络超时',
  505: 'http版本不支持该请求',
}

const beforeRequest: BeforeRequestHook[] = [
  (request: KyRequest) => {
    // 获取token 这里模拟一下
    const token = 'xxxxx'
    if (token)
      request.headers.set('token', token)
  },
]

const beforeError: BeforeErrorHook[] = [
  (error: HTTPError<unknown>) => {
    const { status } = error.response
    // 可以用组件库的方法提示错误
    // 比如 ElMessage ElNotification
    console.log(networkErrMap[status] ?? '其他网络错误')
    return error
  },
]

export { beforeError, beforeRequest }

以上