@cloud-ts/http
v1.0.2
Published
web http request
Readme
title: http
Http
http 基于 axios 提供统一的请求服务,支持自定义错误处理、授权处理、请求数据封装等特性
Install
yarn add @cloud-ts/httpUsage
// src/utils/http.js
import { message } from 'antd';
import Http from '@cloud-ts/http'
export default Http.create({
servers: {
WEB: 'http://service.com/',
},
errorMessageHandler(msg, unlock) {
message.error(msg);
unlock();
},
authFailureCodes: ['0001','002'],
authFailureHandler() {
// logout
}
})
// src/api/order.js
import http from 'src/utils/http'
const api = {
getOrderList: '/order/list',
getOrderDetail(data, config) {
return this.post(`/order/${data.orderId}`, data, config)
},
updateOrder: '/order/:orderId/update',
}
export http.createService<typeof api>({
api,
domain: 'WEB',
})
// src/pages/OrderList.js
import orderService from '@/api/order';
orderService.getOrderList();
orderService.getOrderList(null, { params: { page: 1, size: 20 }});
orderService.getOrderDetail({ orderId: 123 })
orderService.updateOrder({orderId: 123, name: 'orderName'})
API
Http.create
Http.create 用于创建 http 实例。建议全局仅存在一个 http 实例,最少需要配置的参数如下:
- authFailureCodes, 授权失败 errorCodes
- authFailureHandler, 授权失败处理
- errorMessageHandler, 错误消息处理
为了统一错误消息格式,若 code 不带下划线,则 sdk 内部会自动将 code 补充到 message 中 examples: { errorCode: 1001001, errorMsg: 系统繁忙,请稍后重试 } 合并之后: error.message = 系统繁忙,请稍后重试(1001001)) 若 code 带下划线,则不做处理
// .src/utils/http.js
import Http from '@cloud-ts/http';
export default Http.create({
servers: {
WEB1: 'http://service1.com/',
WEB2: 'http://service2.com/',
},
authFailureCodes: [''],
errorMessageHandler() {},
authFailureHandler() {
// logout
},
});http 实例属性:
- instance, axios 实例
- get,get 请求方法
- post,post 请求方法
- request,request 请求方法
- createService, 通过 api 定义创建 service
createService
createService 根据 api 定义自动创建 service,主要用于简化 service 的编写。
createService 参数
createService 支持以下参数:
- http options, 与 http 实例的参数是一致的,且会覆盖 http 实例的参数
- api 请求定义对象,主要用于简化 service 编写。
createService <
typeof api >
{
api: {},
...httpOptions,
};api 是一个 plain object 对象,key 为请求的方法名,value 为请求的 url 或者函数.
value 为 url
只需要定义 key 以及 url 即可,http 模块会自动转换为 function. method 默认为 post,如果需要发送 get 请求,url 中添加 GET 前缀
import { createService } from '@cloud-ts/http'
import http from '@/utils/http'
const api = {
getContractLogList: 'GET /contract/operate_log/list',
updateContract: '/contract/operate_log/list',
}
export createService<typeof api>({
api,
domain: 'WEB',
})
// ./src/pages/xxx.js
import contractService from '@/apis/contract.js'
contractService.getContractLogList({ contractId: 123 }, { type: 'form' })value 为函数
如果需要自定义请求处理逻辑,也可以将 value 定义为 function,自主控制请求的逻辑。
value 函数执行时,会自动绑定 createService 创建的 http 实例为 context,故函数内部可以使用this.post、this.get、this.request来发送 post 请求。
// api/xx/xx.js
import { createService } from '@cloud-ts/http'
import http from '@/utils/http'
const api = {
getContractLogList: '/contract/operate_log/list',
getContractProductPage(data) {
return this.post('/contract/product/page', data, {
requestType: 'form'
})
}
}
export createService<typeof api>({
api,
})建议使用 createService 时设置泛型类型,便于类型判断以及 vscode 中代码提示.
const api = {
getUsers: '/api/users/',
updateUser: '/api/update/user',
};
const service =
createService <
typeof api >
{
api,
http,
serverId: 'OTMS_WEB_PLUS',
};
service.getUserList(); // Property 'getUserList' does not exist on type 'IServiceInstance<T>'
service.getUsers(); // vscode 代码提示,会列出 api 中定义的 keysservice 实例
createService 函数会返回 service 实例,主要包含两部分属性:
- http 实例属性,createService 内部会创建一个新的 http 实例
- api 定义,自动将 api 中的 key、value 转换为 service 函数
const api = {
getUsers: '/api/users/',
updateUser: '/api/update/user'
}
const service = createService<typeof api>({
api,
http,
serverId: 'OTMS_WEB_PLUS',
})
// service 属性
service = {
instance, // axios实例
request,
get,
post,
getUsers() {},
updateUser() {},
}
Http.createError
用于封装 response error 信息,仅在添加自定义 response 拦截器时需要用到
Features
servers
系统依赖的服务地址,建议根据 env 中的环境变量注入
import http from '@cloud-ts/http'
export default Http.create({
servers: {
OTMS_WEB_PLUS: process.env.OTMS_SERVER,
BMS_WEB_PLUS: process.env.BMS_SERVER
}
...
})domain
接口对应的后端服务名称,依赖于 http 实例的 servers 配置。此参数,建议仅在 createService 函数使用。中间件会自动将 servers[domain] 作为 prefix,补充到 url 中。
prefix
通过 prefix 配置服务的域名或者前缀, 在实际业务中,prefix 一般通过构建配置中的环境信息获取。建议每个后端服务创建一个 service 实例
const bms = Http.create({
prefix: process.env.BMS,
});X-NT-App-Meta
接入 stein 的项目,默认会在请求头加上 X-NT-App-Meta。
// request内置中间件处理逻辑
if (window.APP_METADATA) {
headers['X-NT-App-Meta'] = JSON.stringify(window.APP_METADATA);
}
}URL 填充
支持动态 URL,从 data 中提取对应的字段进行 URL 填充,并且 data 会过滤掉 URL 中填充的字段。
const api = {
updateOrder: '/api/order/:orderId/update',
};
const service =
createService <
typeof api >
{
api,
};
// url 被解析为 /api/order/123/update
// data 过滤掉orderId,变成 {orderName: 'name'}
service.updateOrder({ orderId: 123, orderName: 'name' });请求数据
http 模块内置了 3 种请求类型(form、formData、json),针对不同的请求类型会自动转换 data 并添加对应的 content-type header。使用时只需要传入 requestType 参数即可
provideAuth
用于统一添加授权信息
// 通过token扩展,获取token的逻辑
const http = Http.create({
provideAuth(config) {
config.headers['AUTH'] = '...';
return config;
},
});requestInterceptors requestInterceptorsHandler
请求拦截器,此配置只能使用在 http 以及 service 参数中。
注意:自定义请求拦截器 requestInterceptors 执行时间在内部请求拦截器之前
const http = Http.create({
requestInterceptors: [
(instance) => {
instance.interceptors.request.use((config) => {
config.headers['X-NT-APP'] = '....';
return config;
});
},
],
requestInterceptorsHandler(mergeInterceptors, config) {
const interceptors = (instance) => {
instance.interceptors.request.use((config) => {
return config;
});
};
mergeInterceptors.concat(interceptors);
return mergeInterceptors;
},
});响应数据处理
axios 请求成功后,会判断是否业务错误:
- 如判断属于业务错误,则直接返回数据 response.data.content
- 如不属于业务错误,则返回 error 对象
http 模块默认通过data.status === 'SUCCESS' 来判断是否业务错误,如果需要自定义判断逻辑,可以传入 validateData 配置
const http = Http.create({
prefix: 'http://api.bms.cn',
validateData(data) {
return (data.success = 'true');
},
});如果需要扩展 response success 处理逻辑,可配置 responseHandler 参数
const http = Http.create({
prefix: 'http://api.bms.cn',
responseHanlder(response) {
const { config, data } = response;
if (data.success) {
return data.data;
}
return Promose.reject(createError(...));
}
});如果配置了 responseHandler 参数,则 validateData 配置可能失效。
响应异常处理
网络或者 axios 异常、请求异常、数据业务错误,都会进入以下异常处理逻辑.
- 判断请求异常,是否属于鉴权失败,如果是的话,则调用 authFailureHandler 参数,并返回 error
- 如果不属于鉴权失败,则调用 errerMessageHandler 参数, 并返回 error
http 模块通过 authFailureStatus 以及 authFailureCodes 判断是否属于鉴权失败。
if (
response.status === authFailureStatus ||
authFailureCodes.includes(errorCode)
) {
authFailureHandler(error);
return Promise.reject(error);
}http 模块自动对 errorMessageHandler 做了加锁的处理,故在 errorMessageHandler 中,如果弹出框消失需要调用传入的 unlock 函数解锁
如果需要自定义响应异常处理,可以传入 responseErrorHandler 来覆盖默认的处理逻辑。
自定义响应拦截器 responseInterceptors responseInterceptorsHandler
支持 request 以及 response 拦截器,此配置只能使用在 http 以及 service 参数中。
注意:自定义拦截器 responseInterceptors 执行时机在内部拦截器之之后
const http = Http.create({
responseInterceptors: [
(instance) => {
instance.interceptors.response.use((response) => {
...
return response;
})
}
],
responseInterceptorsHandler(mergeInterceptors, config) {
const interceptors = (instance) => {
instance.interceptors.response.use((response) => {
return response;
});
};
mergeInterceptors.unshift(interceptors);
return mergeInterceptors;
},
});配置参数
http 支持三层请求参数配置,request 级参数优先级最高。
- http 参数
- service 参数
- request 参数
配置参数如下:
| name | required | type | default | description | | | | --------------------------- | -------- | --------------------------------------------------------------------------------- | -------------------- | ---------------------------------------- | -------- | ------------ | | servers | false | object | - | http 服务依赖的 server | | | | domain | false | string | - | 与 servers 搭配使用,server domain name | | | | prefix | false | string | - | 请求前缀 | | | | requestType | false | 'json' \ | 'form' \ | 'formData' | json | 请求数据类型 | | responseHandler | false | ( response : AxiosResponse ) => AxiosPromise | - | 请求成功处理函数 | | | | validateData | false | ( data : unknown ) => boolean | - | 判断请求数据是否业务错误 | | | | errorCodeMap | false | { [ code : string ]: string } | - | error code | | | | authFailureCodes | true | string[] | - | 鉴权失败错误 codes | | | | authFailureStatus | false | number | 401 | 鉴权失败状态码 | | | | errorMessageHandler | true | (message: string, unlock: () => void, error: IHttpError) => void | - | 错误消息处理函数 | | | | responseErrorHandler | false | (error: IHttpError) => Promise | - | 响应错误处理函数 | | | | requestInterceptors | false | IHttpInterceptor[] | - | 请求拦截器,不支持在 request 参数中配置 | | | | responseInterceptors | false | IHttpInterceptor[] | - | 响应拦截器 ,不支持在 request 参数中配置 | | | | requestInterceptorsHandler | false | (mergeInterceptors:IHttpInterceptor[], config: IHttpConfig) => IHttpInterceptor[] | - | 自定义请求拦截器处理函数 | | | | responseInterceptorsHandler | false | (mergeInterceptors:IHttpInterceptor[], config: IHttpConfig) => IHttpInterceptor[] | - | 自定义响应拦截器处理函数 | | | | runtimeEnv | false | 'web'\ | 'wxMiniProgram' | 'web' | 运行环境 | | | needCache | false | boolean | false | 请求是否需要缓存结果 | | | | cacheTime | false | number | 24 _ 60 _ 60 * 1000 | 请求缓存时长 | | | | ...axios 配置 | - | - | - | - | | |
