基于 fetch API 封装, 提供更友好便捷的 RESTFul 操作。
yarn add @mini-code/request
import { RequestClass } from '@mini-code/request';
// 构造 $R 请求实例
const $R = new RequestClass();
// 可以为每一个请求对象设置配置
$R.setConfig({
baseUrl: 'https://example.com', // 默认的请求地址
commonHeaders: {} // 所有的请求 headers
});
const getRes = await $R.get('/path');
const postRes = await $R.post('/path', {
ID: '123'
});
const putRes = await $R.put('/path', {
ID: '123'
});
const delRes = await $R.del('/path', {
ID: '123'
});
// get, 使用 params 自动转换成对应的 url
// 最终请求: ${baseUrl}/item-list?id=123&other=123
let res = await $R.get({
url: '/item-list',
headers: {},
params: {
id: 123,
other: 321
},
isBase64: false // 用于加密 params 的值
});
const postData = {
username: 'aaa',
password: 'bbb'
};
const reqOptions = {
}
let res = await $R.post('/postUrl', postData, reqOptions);
let res = await $R.put('/postUrl', postData, reqOptions);
let res = await $R.del('/postUrl', postData, reqOptions);
let res = await $R.patch('/postUrl', postData, reqOptions);
reqOptions 参数结构
interface RequestParams {
/** 当前请求的 headers */
headers?: {};
/** 把参数 params 中转化成 query url */
params?: Map;
/** 如果当前请求发生错误,则触发的回调 */
onError?: (event) => void;
}
const reqOptions: RequestParams = {
}
// reqParams 数据结构
interface BaseRequestParams {
/** 请求的 url,将拼接在 baseUrl 之后 */
url: string;
/** 请求的 http 方法 */
method?: RequestMethod;
/** 当前请求的 data */
data?: {};
/** 当前请求的 headers */
headers?: {};
/** 当前请求的 params,用于封装成 query url */
params?: ParamEntity;
/** 如果当前请求发生错误,则触发的回调 */
onError?: (event) => void;
}
const reqParams: BaseRequestParams = {
url: '/postUrl',
data: {},
headers: {},
params: {
id: '123'
}
}
let res = await $R.post(reqParams);
let res = await $R.put(reqParams);
let res = await $R.del(reqParams);
let res = await $R.patch(reqParams);
基础请求 API,上述 API 均为此 API 的封装
interface RequestParams {
url: string;
method?: RequestMethod;
data?: {};
headers?: {};
params?: ParamEntity;
onError?: (event) => void;
}
const requestOptions: RequestParams = {
url: '/requestUrl',
method: 'POST',
data: {},
header: FetchHeader,
params: {},
}
// 这样就发起一个 post 请求
const res = $R.request(requestOptions);
所有 request API 都返回统一的 ResData 数据结构
interface ResData {
/** 由开发者自定义的返回结构 */
[key: string]: any;
/** 如果返回的结果是 string 类型,则封装在此字段 */
__text?: string;
/** 原生的 fetch Request */
__originReq?: Request;
/** 原生的 fetch Response */
__originRes?: Response;
/** 是否发生 http 错误
* 由 $R.checkStatus 回调返回
* 并且将会触发传入到 request api 中的 onError
*/
__err?: string;
}
const res: ResData = $R.post('', data);
// 统一的检查 res status 的状态,如果 return false,则触发 onErr
$R.checkStatus = (originRes) => {
return true;
}
如果订阅了 $R
提供的事件 onRes
onErr
,每次都会触发
// 每当有 res 的时候执行
$R.on('onRes', (resDetail) => {
resDetail = {
data: {},
originRes: {},
originReq: {},
err: null
}
});
// 每当发生错误时执行
$R.on('onErr', (resDetail) => {
resDetail = {
data: {},
originRes: {},
originReq: {},
err: errMsg
}
});
$R 将根据 checkStatus 返回值判断是否进入错误处理流程, 错误处理流程有两种方式
- 订阅
$R.on('onErr', errHandle = () => {})
- 为每一个请求传入 onError 回调
$R.get({ url: '', onError: errHandle = () => {} })
注意: 如果传入了 onError 回调,则不执行通过 $R.on('onErr') 订阅的回调
// override checkStatus
$R.checkStatus = (fetchRes: Response): boolean => fetchRes.status !== 200
// 如果传入了 onError 回调,则不执行通过 $R.on('onErr') 订阅的回调
$R.get({
url: '/get-stuff',
onError: (data) => {
console.log(data)
}
})
$R.on('onErr', function errHandle(data) {
console.log(data)
})
中间件处理有两个触发时机, 一旦注册,则每次请求都会触发,并且原来用于提交的 data 将会被中间件返回的值替换。
before
: 发起 request 前after
: 收到 response 后,返回数据前
const before = (reqData) => {
return reqData;
}
const after = (resData) => {
return resData;
}
$R.use([before, after])
let postRes = await $R.post('/item-list', data, options);
通讯加密
import { encrypt, decrypt } from '@mini-code/request/request-middleware/encrypt-helper';
import { compress, decompress } from '@mini-code/request/request-middleware/compress-helper';
const encryptKey = '123';
// 使用加密解密
$R.use([encrypt(encryptKey), decrypt(encryptKey)]);
// $R 会将 {ID: '321'} 以 '123' 为加密 key 进行 rc4 加密并发送到服务器
// 收到响应后以同样方式解密,如果服务端返回的数据也时同样方式加密的话
const resPost = await $R.post(testUrl + '/encrypt', {
ID: '321'
});
// 使用内容压缩
// dataWrapper、dataWrapperBeforeDecompress、dataWrapperAfterDecompress 均为格式调整回调,
interface CompressParams {
data: {};
isCompress: boolean;
}
interface DecompressParams {
data: string;
isCompress: boolean;
}
const dataWrapper(data: CompressParams): CompressParams => {};
const dataWrapperBeforeDecompress(data: DecompressParams): DecompressParams => {};
const dataWrapperAfterDecompress(data: DecompressParams): DecompressParams => {};
$R.use([
compress(limitedLen, dataWrapper),
decompress(dataWrapperBeforeDecompress, dataWrapperAfterDecompress)
]);
// 如果消息体的长度大于 limitedLen,则会将消息进行 lzma 压缩
interface RequestParams {
url: string;
method?: RequestMethod;
sendType?: RequestSendTypes;
data: {};
headers?: {};
params?: ParamEntity;
returnRaw?: boolean;
onError?: Function;
}
interface RequestConfig {
baseUrl: string;
commonHeaders: {};
timeout: number;
resMark: string;
errMark: string;
}
interface MiddlewareOptions {
after?: Function | Function[];
before?: Function | Function[];
}
// 底层 request API
$R.request(params: RequestParams)
// 设置 $R 配置
$R.setConfig(config: RequestConfig)
// 使用中间件
$R.use(options: MiddlewareOptions | Function[])
// 同 $R.use([before])
$R.useBefore(Function | Function[])
// 同 $R.use([null, after])
$R.useAfter(Function | Function[])
// url 包装
$R.urlFilter(path: string, params?: ParamEntity)
// 上传
$R.upload(path: string, data: RequestInit["body"])
$R.request
为通用底层接口,其他的 $R.get
$R.post
$R.del
$R.put
$R.patch
均为该接口的上层应用封装。
// 其他方式, options 同 fetch API,sendData 如果是 js,将自动做 header 对应的转换
let res = await $R.request({
url, data, headers, method = 'POST',
returnRaw = false, // 是否返回完整的 res 状态 return returnAll ? res : res.data
...other
});
用于解析前端的 url
的 API
import {
toBase64Str, fromBase64Str,
getUrlParams, searchUrlParams, urlParamsToQuery, openWindowUseHashUrl,
resolveUrl, decodeHashUrl
} from '@mini-code/request/url-resolve';
const urlParamsConfig = {
url: 'https://ss.com',
params: {
id: '1',
req: {
sessID: 123,
username: 'alex',
}
},
toBase64: false // 如果为 true,则将值进行 base64 转换
}
urlParamsToQuery(urlParamsConfig); // 输出 'https://ss.com?id=1&req={sessID:123,username=alex}'
// 若此时的 url 为 'https://ss.com?id=1&req={sessID:123,username=alex}'
const res = getUrlParams(id); // res = 1
resolveUrl('https://a.com', 'path1', 'path2'); // 输出 'https://a.com/path1/path2'