http-data-request
基于 axios 二次封装,可灵活适配的网络数据请求库
项目状态
版本更新内容请访问 Changelog
功能特性
- 自动化保存与应用身份令牌
- 统一处理异常信息
- 可自定义状态码
- 可自定义身份授权数据节点
- 提供各请求方法的快捷函数
- 提供取消当前所有请求函数
设计背景
http-data-request
适用于网页与服务器交互应用自定义编码体系,而不直接使用原生 http 状态码方案的场景
业务数据格式
服务器对于系统内业务请求均响应 http 200 状态,响应数据格式如下
{
// 业务状态码
"code": 0,
// 业务异常信息,非异常情况仅输出 "ok"
"msg": "ok",
// 业务数据
"data": {}
}
业务状态码 code
通常有以下几种情况
0
请求成功10
access token 失效11
refresh token 失效- 其他业务异常
身份认证模式
插件提供了两种身份认证模式,两者的区别在于身份令牌失效的处理不同
认证成功处理流程
流程中 将令牌存储本地存储
与 携带令牌发起请求
均为插件自动处理的行为
认证失败处理流程
双 token 模式
应用 access token 短时效,refresh token 长时效
- 携带 access token 执行数据请求
- 响应 access token 失效状态
{ code: 10, ... }
- http-data-request 自动使用 refresh token 发送刷新 access token 请求
- 响应成功则更新 token 相关信息,并重新发起数据请求
- 响应失败则认为用户身份认证已失效,需重新登录
{ code: 11, ... }
单 token 模式
应用 access token 长时效模式
- 携带 access token 执行数据请求
- 响应 refresh token 失效状态
{ code: 11, ... }
- 失败则认为用户身份认证已失效,需重新登录
安装
将 http-data-request
组件安装到项目中
npm i http-data-request
yarn add http-data-request
pnpm add http-data-request
在项目中添加一个文件,例如 /src/config/http/index.js
,用于设置 http-data-request 的全局配置并导出各功能函数
import { useHttpDataRequest } from 'http-data-request'
import type { HttpDataRequestOptions } from 'http-data-request'
const options: HttpDataRequestOptions = {
baseUrl: 'https://example.com/api',
}
export const {
http, get, post, put, patch, del, cancel
} = useHttpDataRequest(options)
在 vite 配置 vite.config.js
中,为 http 的项目安装模块目录设置别名
import { fileURLToPath, URL } from 'node:url'
import { resolve } from 'path'
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@api': fileURLToPath(new URL('./src/api', import.meta.url)),
'@http': fileURLToPath(new URL('./src/config/http', import.meta.url))
}
},
...
})
应用以上配置后,在项目的任意位置,都可以直接使用 @http
别名来引用 http 相关的函数
基础设定
快捷函数
在 useHttpDataRequest
创建的函数集中,http
函数是数据请求的核心函数,而 get、post、put、patch、del 则是各请求方法的快捷函数
get('/user/1')
// 等价于
http('/user/1', undefined, { method: 'GET' })
http
默认的请求方法是 POST
url
提供的 url 若是一个相对路径,将会自动应用 baseUrl
进行拼接
const options: HttpDataRequestOptions = {
baseUrl: 'https://example.com/api',
}
get('/user/1')
此处实际请求了 https://example.com/api/user/1
地址
get('https://other-example.com/api/user/1')
而 url 以 http/https
开头,将会直接使用该地址,不再拼接 baseUrl
内容
该设定提供了在系统内快速应用基础地址的编码简洁性,又保留了直接访问其他网站地址的灵活性
不匹配的响应格式
使用 http-data-request
请求数据成功,响应格式如下
interface HttpDataRequestBody{
code: number
msg: string
data: any
}
若响应数据格式与 HttpDataRequestBody
不匹配,将直接返回该数据,但与此同时全局异常处理在当次请求中将不会生效
应用实例
项目 API 定义
// src/api/user.js
import { get, post } from '@http'
export function getUser (userId) {
return get(`/user/${userId}`)
}
应用于组件/页面中
<template>
<div>
<div>
User name: {{ user.name }}
</div>
<div>
User age: {{ user.age }}
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { getUser } from '@api/user'
const user = ref({})
getUser(10).then(data => { user.value = data })
</script>
取消请求
取消当前正在执行的所有请求
<template>
<div>
<div>
...order form
</div>
<button
type="button"
@click="save"
>Save order</button>
<!--
Clicking before the data is saved successfully
will cancel the data request
-->
<button
type="button"
@click="cancel"
>Cancel</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { DialogMessageSuccess } from 'v-dialogs'
import { cancel } from '@http'
import { saveOrder } from '@api/order'
function save () {
saveOrder({ ...formData }).then(() => {
DialogMessageSuccess('Order saved successfully')
})
}
</script>
全局配置
这里使用了 v-dialogs 组件作为示例,用于在对话框中显示异常信息内容
import {
useHttpDataRequest,
EXCEPTION_BUSINESS,
EXCEPTION_AUTH_INVALID
} from 'http-data-request'
import type { HttpDataRequestOptions } from 'http-data-request'
import { DialogMessageError, DialogAlertError } from 'v-dialogs'
import { logout } from './auth'
const options: HttpDataRequestOptions = {
baseUrl: 'https://example.com/api',
// global exception handle
exception (message, type) {
// display business exceptions message
if (type === EXCEPTION_BUSINESS) {
DialogMessageError(message)
return
}
// display rest of other exceptions message
DialogAlertError(message)
// some action for user authorization expired
if (type === EXCEPTION_AUTH_INVALID) {
// cancel all current request when
cancel()
// logout and redirect to login page
logout()
}
}
}
export const {
http, get, post, put, patch, del, cancel
} = useHttpDataRequest(options)
上面的代码是全局异常处理在项目中的典型应用,其中有三部分处理内容
- 静默式展示业务异常信息
- 模态提示其他异常信息,该提示需要用户确认后才会继续,例如系统底层异常、网络异常、身份认证失效等
- 当身份令牌失效时,取消所有当前请求并退出登录
设置了全局异常处理后,各类型异常信息将会自动展示,则业务代码中无需处理异常信息,仅需专注于处理业务逻辑即可
应用环境变量
baseUrl
选项指定了网络请求的基础网址前缀,在实际的项目应用中,需要针对不同的工作环境设置不同的地址
以 vite
工具链为例,在项目中创建以下三个 .env
环境配置文件
# .env.development
VITE_BASE_URL=https://exapmle-dev.com/api
# .env.alpha
VITE_BASE_URL=https://exapmle-test.com/api
# .evn.production
VITE_BASE_URL=https://exapmle.com/api
设置了环境变量配置后,通过 import.meta.env.VITE_SOME_KEY
访问变量内容
const options: HttpDataRequestOptions = {
baseUrl: import.meta.env.VITE_BASE_URL
}
这样在不同环境的开发或构建时,会自动应用不同环境指定的基础网络地址
请求头身份令牌
在登录成功后,后续的数据请求会在请求头中添加身份令牌,默认设置下会添加以下字段
{
'Authorization': 'Bearer access-token-value'
}
自定义属性名以及不添加 Bearer
前缀的设置
const options: HttpDataRequestOptions = {
tokenPrefix: false,
keys: {
header: 'x-http-request-access-token'
}
}
应用该设置,请求头携带的 token 属性与值如下
{
'x-http-request-access-token': 'access-token-value'
}
响应状态码
假设服务器响应的状态码方案如下
// 成功
{ "code": 1000, "msg": "ok", "data": { ... } }
// access token 失效
{ "code": 1100, "msg": "access token invalid", "data": {} }
// refresh token 失效
{ "code": 1200, "msg": "refresh token invalid", "data": {} }
根据服务器响应的状态码,设置 statuses
选项中的自定义状态码项目如下
const options: HttpDataRequestOptions = {
baseUrl: 'https://example.com/api',
statuses: {
success: 1000,
invalidAccessToken: 1100,
invalidRefreshToken: 1200
}
}
如此 http-data-request 则一一对应了服务器响应的各种场景状态码
认证授权数据节点
http-data-request 会自动抓取身份令牌并将数据保存至 LocalStorage
中,插件默认匹配的数据格式如下
{
access: {
accessToken: 'access-token-value',
refreshToken: 'refresh-token-value',
expiresIn: 10086
}
}
插件在处理数据请求返回结果时,始终会检测是否存在 access
数据节点,存在则自动进行存入或替换。这一机制无需手动处理 token 信息保存至本地存储的操作,统一 token 信息本地存储的位置与行为
也可以利用该机制实现自动登录的功能
const options: HttpDataRequestOptions = {
keys: {
dataSet: 'accessData',
accessToken: 'accessTokenKey',
refreshToken: 'refreshTokenKey',
expiresIn: 'expiresOn'
}
}
该自定义节点设置,匹配了以下服务器的响应数据格式
{
accessData: {
accessTokenKey: 'access-token-value',
refreshTokenKey: 'refresh-token-value',
expiresOn: 10086
}
}
当 access token 失效时,插件会自动发起刷新 token 的请求(请求的位置由 refreshUrl
选项指定),该请求的数据体如下
{
refreshToken: 'refresh-token-value'
}
需要自定义请求体的字段名,可通过 keys.paramRefreshToken
选项进行设置
const options: HttpDataRequestOptions = {
keys: {
paramRefreshToken: 'refreshTokenValue'
}
}
应用该设置后,刷新 access token 时发送的请求体如下
{
refreshTokenValue: 'refresh-token-value'
}
API
http-data-request 项目安装函数
function useHttpDataRequest(
options: HttpDataRequestOptions
): HttpDataRequestMethods
useHttpDataRequest
输入参数 HttpDataRequestOptions
的类型描述
interface HttpDataRequestOptions {
/**
* 插件语言
* @default `en`
*/
language?: 'en' | 'zh-chs'
/**
* 基础请求路径
* @default `/`
*/
baseUrl: string
/**
* 执行刷新 access token 时的请求路径
* @default `/auth/refresh-token`
*/
refreshUrl?: string
/**
* @default 0
*/
expiresIn?: number
/**
* 指定请求超时的时间,单位为毫秒
* @default 10000
*/
timeout?: number
/**
* 请求头携带的 token 是否添加 `Bearer` 前缀
* @default true
*/
tokenPrefix?: boolean
/** 自定义数据节点名 */
keys?: {
/**
* 授权相关数据的总节点名
* @default `access`
*/
dataSet?: string
/**
* access token 身份令牌
* @default `accessToken`
*/
accessToken?: string
/**
* refresh token 用于刷新 access token 令牌
* @default `refreshToken`
*/
refreshToken?: string
/**
* 令牌失效时间
* @default `expiresIn`
*/
expiresIn?: string
/**
* 发起刷新 access token 令牌时,请求体中携带 refresh token 的属性名
* @default `refreshToken`
*/
paramRefreshToken?: string
/**
* 请求头中用于携带 access token 令牌的属性名
* @default `Authorization`
*/
header?: string
}
/** 自定义响应状态码 */
statuses?: {
/**
* 请求成功
* @default 0
*/
success?: number
/**
* access token 失效
* @default 10
*/
invalidAccessToken?: number
/**
* refresh token 失效
* @default 11
*/
invalidRefreshToken?: number
}
/** 请求异常全局处理 */
exception?: (message: string, type: EXCEPTION_TYPE) => void
}
type EXCEPTION_TYPE =
| 'exception-business'
| 'exception-auth-invalid'
| 'exception-system'
useHttpDataRequest
执行后创建的函数集 HttpDataRequestMethods
的类型描述
interface HttpDataRequestMethods {
/**
* http 数据请求核心函数
*/
http: typeof HttpDataRequest
/**
* http 请求应用 get、post、put、patch 与 delete 请求方法的快捷函数
*/
get: typeof HttpDataRequest
post: typeof HttpDataRequest
put: typeof HttpDataRequest
patch: typeof HttpDataRequest
del: typeof HttpDataRequest
/**
* 取消所有当前的数据请求
*/
cancel: () => void
}
function HttpDataRequest(
// 数据请求地址
url: string,
// 请求数据
data: any,
// axios 原生请求配置参数
options: AxiosRequestConfig
): Promise<any>
完整的 axios 配置参数请查看 axios-request-config