@pluve/fetch2
v0.0.15
Published
fetch abort
Downloads
10
Readme
@pluve/fetch2
基于 fetch 封装,保留与
@pluve/fetch
基本一致的用法。若用到文件上传,请参考@pluve/file-utility
或者@pluve/storage-client
。
安装
yarn add @pluve/fetch2
引用
import FetchAgent from '@pluve/fetch2';
使用说明
@pluve/fetch 支持自定义请求头,可动态设置鉴权 token,实现了请求和响应结果拦截器,可对响应报文统一处理。支持超时时间配置,debug 模式,支持终止请求等。
类型说明
IRequestParams
interface RequestInit {
/** A BodyInit object or null to set request's body. */
body?: BodyInit | null;
/** A string indicating how the request will interact with the browser's cache to set request's cache. */
cache?: RequestCache;
/** A string indicating whether credentials will be sent with the request always, never, or only when sent to a same-origin URL. Sets request's credentials. */
credentials?: RequestCredentials;
/** A Headers object, an object literal, or an array of two-item arrays to set request's headers. */
headers?: HeadersInit;
/** A cryptographic hash of the resource to be fetched by request. Sets request's integrity. */
integrity?: string;
/** A boolean to set request's keepalive. */
keepalive?: boolean;
/** A string to set request's method. */
method?: string;
/** A string to indicate whether the request will use CORS, or will be restricted to same-origin URLs. Sets request's mode. */
mode?: RequestMode;
/** A string indicating whether request follows redirects, results in an error upon encountering a redirect, or returns the redirect (in an opaque fashion). Sets request's redirect. */
redirect?: RequestRedirect;
/** A string whose value is a same-origin URL, "about:client", or the empty string, to set request's referrer. */
referrer?: string;
/** A referrer policy to set request's referrerPolicy. */
referrerPolicy?: ReferrerPolicy;
/** An AbortSignal to set request's signal. */
signal?: AbortSignal | null;
/** Can only be null. Used to disassociate request from any Window. */
window?: null;
}
export interface IRequestParams extends RequestInit {
key?: string; // 接口请求标识,用于取消请求
url: string; // 接口请求链接
method?: RequestMethodsEnum; // 请求方式
headers?: ICustomHeader; // 接口请求头,可与全局的请求头合并
useGlobalHeader?: boolean; // 是否使用全局请求头
body?: any; // 请求体
submitDataType?: 'json' | 'form'; // 数据提交类型,支持application/json 和 application/x-www-form-urlencoded
timeout?: number; // 接口超时时间,单位毫秒,默认15000
timeStamp?: number; // 接口发起时的时间戳
abortController?: AbortController; // 取消请求的控制器
reqInterceptor?: IRequestInterceptor; // 请求拦截器
respInterceptor?: IResponseInterceptor; // 响应拦截器
[key: string]: any; // 支持携带自定义请求参数,可在拦截器中使用
}
Response
interface Body {
readonly body: ReadableStream<Uint8Array> | null;
readonly bodyUsed: boolean;
arrayBuffer(): Promise<ArrayBuffer>;
blob(): Promise<Blob>;
formData(): Promise<FormData>;
json(): Promise<any>;
text(): Promise<string>;
}
interface Response extends Body {
readonly headers: Headers;
readonly ok: boolean;
readonly redirected: boolean;
readonly status: number;
readonly statusText: string;
readonly type: ResponseType;
readonly url: string;
clone(): Response;
}
IExceptionInfo
export interface IExceptionInfo {
code: number; // EXCEPTION_KEYS
message: string;
data?: string | number;
}
const EXCEPTION_KEYS = {
ABORT_EXCEPTION_KEY: 10000, // 请求终止
TIMEOUT_EXCEPTION_KEY: 10001, // 请求超时
NETWORK_ERROR_EXCEPTION_KEY: 10002, // 请求网络异常
INTERCEPT_AT_GLOBAL_LEVEL: 10003, // 被全局拦截器拦截
INTERCEPT_AT_API_LEVEL: 10004, // 被接口拦截器拦截
REQUEST_REDIRECT: 10005, // 请求重定向
RESPONSE_400_PLUS: 10006, // 400相关响应
RESPONSE_OTHER: 10007, // 其他异常
REQUEST_CROSS: 10008, // 请求跨域
RESPONSE_TIME_TRIGGER_THRESHOLD: 10009, // 接口耗时触发阀值
};
接口
setDebug
设置是否为 debug 模式。debug 模式下,控制台会打印详细的接口请求及响应信息,默认为关闭,可在开发测试模式下开启,建议在生产环境关闭。
FetchAgent.setDebug(true);
setupTimeout
设置超时时间,默认为 15s,单位为毫秒
FetchAgent.setTimeout(15000);
setupApiTimeCostThreshold
设置接口响应时长阀值,默认 1000ms,超过该值则会在控制台打印接口响应时长
FetchAgent.setupApiTimeCostThreshold(1000);
setupDefaultGlobalHeaderGenerator
设置统一请求头信息,若某个接口请求头有特殊要求,可在 GET、POST 方法中设置
FetchAgent.setupDefaultGlobalHeaderGenerator(() => ({
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
}));
setupDefaultCommonReqBodyGenerator
在请求体中设置通用参数,如鉴权信息等。若表单提交,则会忽略该方法设置的参数。
FetchAgent.setupDefaultCommonReqBodyGenerator(() => ({
openx_header: 'xxx',
}));
setupReqInterceptor
接口请求全局拦截器,若返回 true,则终止请求。接口级别的拦截器优先级高于全局拦截器。
FetchAgent.setupReqInterceptor((req: IRequestParams) => false);
setupRespInterceptor
响应结果全局拦截器,若返回 true,则终止后续流程。可用于 token 过期、异常处理等场景。接口级别的拦截器优先级高于全局拦截器。此处读取 response 响应数据应先 clone,否在 return false 后会导致响应体重复使用的异常。
FetchAgent.setupRespInterceptor((requestParams: IRequestParams, response: Response) => false);
setupOnError
设置全局错误处理函数 接口响应码非 200 时会回调;
接口响应超时时会回调;
接口响应时长超过警告阀值时会回调;
可在异常日志上报场景下使用。
FetchAgent.setupOnError((err: IExceptionInfo, requestInfo: IRequestParams) => {
console.log(error);
});
sendRequest
发送请求
① 返回 Promise,若请求被拦截,则返回 undefined。
② 支持 GET、POST、PUT、DELETE、PATCH 等请求方式。
③ 支持请求头、请求体、请求参数、请求超时、请求取消等功能。
④ 支持传入泛型,返回指定类型的数据。
/**
* 发送请求
* @param requestInfo
*/
export const request = <T = unknown>(requestInfo: IRequestParams): Promise<T> => {
const requestParams = buildRequestOptions(requestInfo);
if (requestParams.reqInterceptor && requestParams.reqInterceptor(requestParams)) {
return;
}
if (handlerBeforeRequest(requestParams)) {
return;
}
requestMap.set(requestParams.key, requestParams);
const apiPromise = doRequest(requestParams);
return handlerApiResponse<T>(requestParams, apiPromise);
};
// 业务服务声明
export const fetchArticle = ({ pageNo, pageSize }: { pageNo: number; pageSize: number }) =>
FetchAgent.sendPost<ApiCommonResponse<IArticleDataItem[]>>({
url: articleService,
body: {
article: { articleType: null, keyword: null },
pageNo,
pageSize,
},
respInterceptor: async (requestParams, response) => {
console.log('respInterceptor: ', requestParams);
// 一定要这样写
// console.log(response.clone().json());
// 这样写报错
// console.log(response.json());
return false;
},
});
// 业务调用
try {
const articleListResp = await fetchArticle({ pageNo: this.pageNo, pageSize: this.pageSize });
this.updateArticles(refresh, articleListResp);
} catch (e) {
this.showError();
}
为了兼容@pluve/fetch,request 接口有以下变种 | 编号 | 方法名 | 说明 | | -- | -- | -- | | 1 | sendRequest | 发送接口请求 | | 2 | sendRequestCustomer | 发送接口请求 | | 3 | sendRequestPure | 发送接口请求 | | 4 | get | 发送 get 请求 | | 5 | sendGet | 发送 get 请求 | | 6 | post | 发送 post 请求 | | 7 | sendPost | 发送 post 请求 |
abortPendingRequestByKey
根据 key 终止请求
export const abortPendingRequestByKey = (key: string) => {
if (!key) {
return;
}
const requestItem = requestMap[key] as IRequestParams;
if (requestItem && requestItem.abortController) {
requestAbortManualFlag.set(key, true);
requestItem.abortController.abort();
requestMap.delete(key);
}
};
FetchAgent.abortPendingRequestByKey('key');
clearRequest
清除 pending 中的请求
export const clearRequest = () => {
// 只要还在此map中的请求,均为pending状态
requestMap.forEach(requestItem => {
if (requestItem.abortController) {
const key = requestItem.key || '';
requestAbortManualFlag.set(key, true);
requestItem.abortController.abort();
}
});
requestMap.clear();
};
FetchAgent.clearRequest();
外部依赖
若低版本浏览器需要依赖 whatwg-fetch
issues 说明
暂无版本计划