0.10.3 • Published 5 months ago

@varlet/axle v0.10.3

Weekly downloads
-
License
MIT
Repository
github
Last release
5 months ago

English | 中文

介绍

基于 axios 的渐进式请求工具。 它不会破坏 axios 原有的能力,帮助您更轻松地处理请求。

快速开始

安装

# 通过 npm, yarn, pnpm 安装

# npm
npm i @varlet/axle -S

#yarn
yarn add @varlet/axle

#pnpm
pnpm add @varlet/axle

发送请求

Axle 归一化了请求函数的参数,并针对不同的业务需求,扩展了更多请求函数,下面是一个简单的例子。

import { createAxle } from '@varlet/axle'

const axle = createAxle(/** @see https://axios-http.com **/)

axle.get('/url', { current: 1, pageSize: 10 }, { headers: {} })
axle.post('/url', { name: 'Axle' }, { headers: {} })

配置

Axle 完全支持 axios 的所有配置能力。

const axle = createAxle(/** @see https://axios-http.com **/)
// axle 内置的 axios ,用法和 axios 一模一样,并且和 axle 共享配置。
const { axios } = axle

axios.defaults.baseURL = 'https://api.example.com'
axios.defaults.headers.common['TOKEN'] = TOKEN
axios.defaults.timeout = 2500

// 添加请求前拦截器
axios.interceptors.request.use(
  (config) => {
    // 请求前处理
    return config
  },
  (error) => {
    // 请求错误处理
    return Promise.reject(error)
  },
)

// 添加请求后返回拦截器
axios.interceptors.response.use(
  (response) => {
    // 任何位于 2xx 范围内的状态码都会导致该函数触发
    // 对响应数据做一些事情
    return response
  },
  (error) => {
    // 任何超出 2xx 范围的状态代码都会导致此函数触发
    // 对响应错误做一些事情
    return Promise.reject(error)
  },
)

Axle & Axios 请求函数

Axle 提供的请求函数可以帮助您更轻松地发送请求。 以下是一些示例,包括与 axios 的比较。 提示:下面只是以 getpost 为例,除此之外 Axle 还支持 optionsheaddeletepatchput 方法。

get

JSON

// axios
axios.get('/url', { params: { id: 1 } })
// axle
axle.get('/url', { id: 1 })

Blob

// axios
axios.get('/url', { params: { id: 1 }, responseType: 'blob' })
// axle
axle.getBlob('/url', { id: 1 })

Text

// axios
axios.get('/url', { params: { id: 1 }, responseType: 'text' })
// axle
axle.getText('/url', { id: 1 })

Document

// axios
axios.get('/url', { params: { id: 1 }, responseType: 'document' })
// axle
axle.getDocument('/url', { id: 1 })

ArrayBuffer

// axios
axios.get('/url', { params: { id: 1 }, responseType: 'arraybuffer' })
// axle
axle.getArrayBuffer('/url', { id: 1 })

Stream

// axios
axios.get('/url', { params: { id: 1 }, responseType: 'stream' })
// axle
axle.getStream('/url', { id: 1 })

post

JSON

和 axios 一致。

// axios
axios.post('/url', { name: 'foo' })
// axle
axle.post('/url', { name: 'foo' })

application/x-www-form-urlencoded

// axios
axios.post('/url', qs.stringify({ name: 'foo' }), {
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
})
// axle
axle.postUrlEncode('/url', { name: 'foo' })

multipart/form-data

// axios
const formData = new FormData()
formData.append('name', 'foo')
formData.append('file', new File())

axios.post('/url', formData, {
  headers: {
    'Content-Type': 'multipart/form-data',
  },
})
// axle
axle.postMultipart('/url', { name: 'foo', file: new File() })

实用工具

通知浏览器下载文件

import { download } from '@varlet/axle'

download(await axle.getBlob('/url', { id: 1 }), 'filename')

同时返回成功响应和错误响应

import { withResponse } from '@varlet/axle'

const { response, errorResponse } = await withResponse(axle.get('/url'))

公共 header 操作

const headers = axle.getHeaders()
axle.setHeader('TOKEN', TOKEN)
axle.removeHeader('TOKEN')

内置拦截器

Axle 提供了一些实用的请求/响应拦截器,并且兼容 axle 和 axios。

axios

import { requestHeadersInterceptor, responseTimeoutInterceptor } from '@varlet/axle'

const headersInterceptor = requestHeadersInterceptor({
  headers: () => ({
    token: localStorage.getItem('token'),
    'Axle-Custom-Header': 'Axle-Custom-Header',
  }),
})

const retryInterceptor = responseRetryInterceptor({ count: 3 })

axios.interceptors.request.use(
  headersInterceptor.onFulfilled,
  headersInterceptor.onRejected,
  headersInterceptor.options,
)
axios.interceptors.response.use(retryInterceptor.onFulfilled, retryInterceptor.onRejected, retryInterceptor.options)

axle

import { requestHeadersInterceptor, responseTimeoutInterceptor } from '@varlet/axle'

axle.useRequestInterceptor(
  requestHeadersInterceptor({
    headers: () => ({
      token: localStorage.getItem('token'),
      'Axle-Custom-Header': 'Axle-Custom-Header',
    }),
  }),
)

axle.useResponseInterceptor(responseRetryInterceptor({ count: 3 }))

拦截器通用参数

每个内置拦截器都支持 include exclude axiosInterceptorOptions (与 axios 拦截器一致)

include & exclude

用于请求过滤,以确定什么请求应该应用该拦截器,支持指定 methodglob 或者 status,使用方式如下。

axle.useResponseInterceptor(
  responseRetryInterceptor({
    count: 3,
    include: ['method:put', 'method:post', 'status:500'],
    exclude: ['/system/**', '/user/addUser', 'status:400'],
  }),
)

内置拦截器一览

名称描述
requestHeadersInterceptor用于自定义请求头
requestMockInterceptor用于模拟数据
requestMd5Interceptor用于对请求参数进行 md5 处理
responseRetryInterceptor用于实现请求异常重试
responseStatusInterceptor用于拦截状态码
responseBlobInterceptor用于拦截 blob 类型
responseTimeoutInterceptor用于归一化超时异常

Vue 组合式 API

Axle 提供了 Vue Composition API 风格的用法,封装了请求的 加载状态, 错误状态, 请求的上下行进度返回数据生命周期 等等,并继承了 axios 的所有配置。

<script setup>
  import { createAxle } from '@varlet/axle'
  import { createUseAxle } from '@varlet/axle/use'

  const axle = createAxle(/** @see https://axios-http.com **/)

  const useAxle = createUseAxle({
    axle,
    // 可选项: useAxle 的默认 immediate, 默认值: true
    immediate: false,
    // 可选项: useAxle 的默认 onTransform
    onTransform: (response) => response,
  })

  const [
    users,
    // 请求触发器
    getUsers,
    // 附加属性
    { loading, error, uploadProgress, downloadProgress, abort },
  ] = useAxle({
    // 请求初始化数据
    value: [],
    // 请求方法
    method: 'get',
    // 请求地址, 可以是 getter 函数
    url: '/user',
    // 是否立即发送请求, 默认值: true
    immediate: false,
    // 请求前是否需要重置 value, 默认值: false
    resetValue: true,
    // 重置 value 是否对 value 进行拷贝
    // 设置为 true 时, 使用 JSON.parse(JSON.stringify(value)) 进行拷贝
    // 设置为一个函数时, 该函数将作为拷贝函数对 value 进行拷贝, 如 v => _.cloneDeep(v)
    cloneResetValue: true,
    // 请求参数, 默认值: {}, 可以是 getter 函数
    params: { current: 1, pageSize: 10 },
    // Axios 配置, see https://axios-http.com, 可以是 getter 函数
    config: { headers: {} },
    // 生命周期
    onBefore(refs) {
      const { data, loading, error, uploadProgress, downloadProgress } = refs
      console.log(data.value, loading.value, error.value, uploadProgress.value, downloadProgress.value)
      // 处理请求前逻辑
    },
    onTransform(response, refs) {
      // 处理数据转换,转换后的数据将成为 users 的值。
      return response.data
    },
    onSuccess(response, refs) {
      // 处理请求成功逻辑
    },
    onError(error, refs) {
      // 处理请求错误逻辑
    },
    onAfter(refs) {
      // 处理请求结束逻辑,无论成功失败都会触发。
    },
  })
</script>

<template>
  <span>{{ users }}</span>
  <span>{{ loading }}</span>
  <span>{{ error }}</span>
  <span>{{ uploadProgress }}</span>
  <span>{{ downloadProgress }}</span>
  <button @click="getUsers">发送请求</button>
  <button @click="abort">中断请求</button>
</template>

并行请求实用工具

Axle 提供了一些并行请求处理工具,请参考以下示例。

<script setup>
  import { createAxle } from '@varlet/axle'
  import { createUseAxle, useAverageProgress, useHasLoading, useValues } from '@varlet/axle/use'

  const axle = createAxle(/** @see https://axios-http.com **/)

  const useAxle = createUseAxle({ axle })

  const [users, getUsers, { loading: isUsersLoading, downloadProgress: usersDownloadProgress }] = useAxle({
    method: 'get',
    url: '/user',
  })

  const [roles, getRoles, { loading: isRolesLoading, downloadProgress: rolesDownloadProgress }] = useAxle({
    method: 'get',
    url: '/role',
  })

  // 所有请求结束时,loading 为 false
  const loading = useHasLoading(isUsersLoading, isRolesLoading)
  // 所有请求结束时,downloadProgress 为 1
  const downloadProgress = useAverageProgress(usersDownloadProgress, rolesDownloadProgress)
  // Ref<[
  //   [{ name: 'foo' }, { name: 'bar' }],
  //   [{ role: 'admin' }, { role: 'user' }]
  // ]> <-
  // [
  //   Ref<[{ name: 'foo' }, { name: 'bar' }]>,
  //   Ref<[{ role: 'admin' }, { role: 'user' }]>
  // ]
  const usersRoles = useValues(users, roles)

  function sendAllRequest() {
    // parallel
    getUsers()
    getRoles()
  }
</script>

<template>
  <span>{{ usersRoles }}</span>
  <span>{{ loading }}</span>
  <span>{{ downloadProgress }}</span>
  <button @click="sendAllRequest">发送全部请求</button>
</template>

API 定义增强

0.9.0 开始支持 createApi,以增强 API 定义能力。

定义 API

import { createAxle } from '@varlet/axle'
import { createApi } from '@varlet/axle/api'
import { createUseAxle } from '@varlet/axle/use'

const axle = createAxle({
  baseURL: '/api',
})

const useAxle = createUseAxle({
  axle,
})

const api = createApi(axle, useAxle)

export const apiGetUsers = api<Response<User[]>>('/user', 'get')

export const apiGetUser = api<Response<User>>('/user/:id', 'get')

export const apiCreateUser = api<Response<User>, CreateUser>('/user', 'post')

export const apiUpdateUser = api<Response<User>, UpdateUser>('/user/:id', 'put')

export const apiDeleteUser = api<Response<User>>('/user/:id', 'delete')

export type Response<T> = {
  data: T
  code: number
  message: string
  success: boolean
}

export interface User {
  id: string
  name: string
}

export interface CreateUser {
  name: string
}

export interface UpdateUser {
  name: string
}

调用 API

const route = useRoute()

const [users, getUsers] = apiGetUsers.use<Response<User[]>>(/** 和 useAxle 一致并且扩展了 pathParams **/)

const [user, getUser] = apiGetUser.use<Response<User>>({
  pathParams: () => ({ id: route.params.id }),
})

async function handleCreate(params: CreateUser) {
  const { success } = await apiCreateUser.load(params)

  if (success) {
    getUsers()
  }
}

async function handleUpdate(params: UpdateUser, id: string) {
  const { success } = await apiUpdateUser.load(params, { id })

  if (success) {
    getUsers()
  }
}

async function handleDelete(id: string) {
  const { success } = await apiDeleteUser.load({}, { id })

  if (success) {
    getUsers()
  }
}

请求触发器增强

v0.10.0 开始, 请求触发器将包含附加属性中的全部属性。

增强前:

<script setup>
  const [users, getUsers, { loading: isUsersLoading }] = useAxle({
    method: 'get',
    url: '/user',
  })

  const [posts, getPosts, { loading: isPostsLoading }] = useAxle({
    method: 'get',
    url: '/post',
  })
</script>

<template>
  <span>{{ isUsersLoading ? 'loading...' : users }}</span>
  <span>{{ isPostsLoading ? 'loading...' : posts }}</span>
  <button @click="getUsers">Send Request</button>
  <button @click="getPosts">Send Request</button>
</template>

增强后:

<script setup>
  const [users, getUsers] = useAxle({
    method: 'get',
    url: '/user',
  })

  const [posts, getPosts] = useAxle({
    method: 'get',
    url: '/post',
  })
</script>

<template>
  <span>{{ getUsers.loading.value ? 'loading...' : users }}</span>
  <span>{{ getPosts.loading.value ? 'loading...' : posts }}</span>
  <button @click="getUsers">Send Request</button>
  <button @click="getPosts">Send Request</button>
</template>
0.10.2

5 months ago

0.10.3

5 months ago

0.9.4

7 months ago

0.9.5

7 months ago

0.10.1

7 months ago

0.10.0

7 months ago

0.9.2

7 months ago

0.9.3

7 months ago

0.9.1

8 months ago

0.9.0

9 months ago

0.8.0

11 months ago

0.7.1

1 year ago

0.7.0

1 year ago

0.6.0

1 year ago

0.5.0

1 year ago

0.5.2

1 year ago

0.5.1

1 year ago

0.4.0

1 year ago

0.3.5

2 years ago

0.3.4

2 years ago

0.3.3

2 years ago

0.3.2

2 years ago

0.3.1

2 years ago

0.3.0

2 years ago

0.2.18

2 years ago

0.2.17

2 years ago

0.2.16

2 years ago

0.2.15

2 years ago

0.2.14

2 years ago

0.2.13

2 years ago

0.2.12

2 years ago

0.2.11

2 years ago

0.2.10

2 years ago

0.1.0

2 years ago

0.1.2

2 years ago

0.1.1

2 years ago

0.0.26

2 years ago

0.0.20

2 years ago

0.0.21

2 years ago

0.0.22

2 years ago

0.0.23

2 years ago

0.0.24

2 years ago

0.0.25

2 years ago

0.0.15

2 years ago

0.0.16

2 years ago

0.0.17

2 years ago

0.0.18

2 years ago

0.0.19

2 years ago

0.0.10

2 years ago

0.0.11

2 years ago

0.0.12

2 years ago

0.0.13

2 years ago

0.0.14

2 years ago

0.2.1

2 years ago

0.2.0

2 years ago

0.2.7

2 years ago

0.2.6

2 years ago

0.2.9

2 years ago

0.2.8

2 years ago

0.2.3

2 years ago

0.2.2

2 years ago

0.2.5

2 years ago

0.2.4

2 years ago

0.0.9

2 years ago

0.0.8

2 years ago

0.0.5

2 years ago

0.0.4

2 years ago

0.0.7

2 years ago

0.0.6

2 years ago

0.0.3

3 years ago

0.0.2

3 years ago

0.0.1

3 years ago

0.0.0

3 years ago