Installations
npm install @alicloud/fetcher
Developer Guide
Typescript
Yes
Module System
CommonJS
Node Version
18.11.0
NPM Version
lerna/6.6.0/node@v18.11.0+arm64 (darwin)
Score
73.6
Supply Chain
92.2
Quality
81.7
Maintenance
100
Vulnerability
99.6
License
Releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (90.14%)
Less (9.02%)
JavaScript (0.83%)
Developer
aliyun
Download Statistics
Total Downloads
41,751
Last Day
12
Last Week
48
Last Month
159
Last Year
3,715
GitHub Statistics
51 Stars
1,989 Commits
13 Forks
9 Watching
14 Branches
8 Contributors
Bundle Size
61.27 kB
Minified
18.35 kB
Minified + Gzipped
Package Meta Information
Latest Version
1.7.9
Package Id
@alicloud/fetcher@1.7.9
Unpacked Size
136.06 kB
Size
29.73 kB
File Count
121
NPM Version
lerna/6.6.0/node@v18.11.0+arm64 (darwin)
Node Version
18.11.0
Publised On
24 Mar 2023
Total Downloads
Cumulative downloads
Total Downloads
41,751
Last day
-7.7%
12
Compared to previous day
Last week
-4%
48
Compared to previous week
Last month
-26.7%
159
Compared to previous month
Last year
-65.4%
3,715
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
5
@alicloud/fetcher
一个类似 axios 的带拦截器的请求包。
为何不用 axios?
- not a fan
- axios 它底层用的是 XHR 不是 fetch
- axios 的 API 设计过于冗长,比如添加拦截器,它是
axios.interceptors.request|response.use
,解除用axios.interceptors.request|response.eject
,而且要传入前者返回的值(数字,存在安全风险) - axios request 拦截器是倒着插入的,response 是顺的,用起来非常别扭
- axios request 拦截器可以传跟 response 拦截器一样传两个函数
- axios request 拦截器一旦出错,真正的请求不会发,但却会触发 response 拦截器中的 fail
- axios 对结果做了封装,要拿里边真正的数据就需要剥洋葱
- axios 的实例貌似无法「封锁」,每个人都可以来干它,可能谁都不知道谁干了什么,这很容易造成问题
- 对 axios 不熟,以上说法可能有失偏颇
INSTALL
1tnpm i @alicloud/fetcher -S
Polyfill
这里对浏览器的依赖主要有两个:fetch 和 Promise:
fetch
在依赖包@alicloud/fetcher-fetch
中用 unfetch 做了 fallback,没有全局 polyfill,应用可自行选择,比如 whatwg-fetchPromise
需要应用代码保证
API
你可以直接用「开箱即用」的 fetcher:
1import fetcher from '@alicloud/fetcher'; 2 3const { 4 request, 5 jsonp, 6 get, 7 delete, 8 post, 9 put, 10 patch 11} = fetcher;
注意,
- 里边的方法可以直接析构出来使用
- 此开箱即用的 fetcher 无法添加拦截器
也可以通过工厂方法 createFetcher
创建自己的 fetcher,这样你便可以对它添加拦截器(当然,添加完最后你也可以选择锁定它以保证不被别的代码干扰)。
1import { 2 createFetcher 3} from '@alicloud/fetcher'; 4 5const fetcher = createFetcher(); 6 7const { 8 interceptRequest, 9 interceptResponse, 10 sealInterceptors 11} = fetcher; 12 13// 添加拦截器 14interceptRequest(fn); 15interceptResponse(fnSuccess, fnFail); 16// 锁定拦截器(你可以通过传参选择封锁对请求还是响应的拦截处理) 17sealInterceptors(); 18 19export default fetcher;
封装自己的工厂?
有的时候,你可能需要封装自己的工厂。
假设,你封装的将作为一个 npm 包,那么你需要在你的包中最好能够输出这里的 所有输出(包括 type)。
拦截器
fetcher 拦截器的设计:
- 接口简单:
interceptRequest
和interceptResponse
,它返回一个解除拦截的无参函数 - 保证顺序
- request 拦截器仅需要一个回调,response 还是保持两个
- request 拦截一旦抛错,即中止
- response 不会被包裹
- 拦截器的最末一个参数是当前的
Fetcher
实例,你可以用它做一些其他的事情,但请保证不会无限循环
创建拦截器最佳实践
不好的例子
一般来说,拦截器可以单独写成 npm 包以便复用,但这个包它不应当有这样的想法:「嗯,调用我的人一定知道怎么使用我。」
你可能会这么写:
1import { 2 Fetcher, 3 FetcherConfig, 4 FetcherError 5} from '@alicloud/fetcher'; 6 7export default (err: FetcherError, fetcherConfig: FetcherConfig, fetcher: Fetcher): void => { 8 // do sth. according to err and config 9 10 const dealt = dealWithError(err, config); 11 12 if (dealt) { 13 return; 14 } 15 16 throw err; // 没处理的错误继续 throw 17};
但这样写不合适。因为它要求使用者必须了解究竟是用 interceptRequest
还是 interceptResponse
,而用 interceptResponse
的时候是第一个回调还是第二个。
使用者需要对你的 interceptor 十分了解才能用它,像这样:
1import createFetcher, { 2 Fetcher 3} from '@alicloud/fetcher'; 4import interceptor from 'interceptor-package'; 5 6const fetcher: Fetcher = createFetcher(); 7 8fetcher.interceptResponse(undefined, interceptor); // 这里会造成困扰,很容易搞错 9 10export default fetcher;
好的例子
以上这么做并不是不对,而是不合适,给使用者造成困扰。而更合适的方式,是你告诉使用者:「嘿,把你的 Fetcher 实例给我,剩下的交给我。」
同时,更更好的是,把你的拦截器,写成一个工厂方法,这样它就可以更具有普适性。
你可以看仓库中的几个拦截器,都是很好的例子:
console-fetcher-interceptor-arms
console-fetcher-interceptor-fecs
console-fetcher-interceptor-req-mock
console-fetcher-interceptor-req-security
console-fetcher-interceptor-res-biz
console-fetcher-interceptor-res-error-message
console-fetcher-interceptor-res-risk
console-fetcher-interceptor-sls
他们的特点:
src/index
export util/intercept
为 default,并可能输出类型 FetcherInterceptorConfig
、FetcherConfigExtra
、FetcherConfigExtended
。
util/intercept
利用的是可能存在的以下三个文件,它们的输入都是 FetcherInterceptorConfig
:
util/create-interceptor-request
→FetcherFnInterceptRequest
util/create-interceptor-response-fulfilled
→FetcherFnInterceptResponseFulfilled
util/create-interceptor-response-rejected
→FetcherFnInterceptResponseRejected
类型说明(任何一个都是可选的):
FetcherInterceptorConfig
如上所说,是拦截器创建时需要的参数。FetcherConfigExtra
是对@alicloud/fetcher
的FetcherConfig
的扩展,用于合适的地方做interface
的extend
FetcherConfigExtended
是扩展后的FetcherConfig
,一般不该被直接用到
拦截器最佳实践
1src/ 2 ├── types/ 3 │ └── index.ts 4 ├── util/ 5 │ ├── ... 6 │ ├── create-interceptor-request.ts 7 │ ├── create-interceptor-response-fulfilled.ts 8 │ ├── create-interceptor-response-rejected.ts 9 │ └── intercept.ts 10 └── index.ts
src/types/index.ts 范例
1import { 2 FetcherConfig 3} from '@alicloud/fetcher'; 4 5// 创建拦截器时的配置参数,将被用于 fetcher 工厂的扩展参数 6export interface IFetcherInterceptorConfig { 7 ... 8} 9 10export interface IFetcherConfigExtra { 11 ... 12} 13 14export interface IFetcherConfigExtended extends FetcherConfig, IFetcherConfigExtra {}
src/util/create-interceptor-request.ts 范例
1import { 2 FetcherFnInterceptRequest, 3 FetcherInterceptRequestReturn 4} from '@alicloud/fetcher'; 5 6import { 7 IFetcherInterceptorConfig, 8 IFetcherConfigExtended 9} from '../types'; 10 11export default function createInterceptorRequest(interceptorConfig: IFetcherInterceptorConfig): FetcherFnInterceptRequest<IFetcherConfigExtended> { 12 // 在这里消费 interceptorConfig 13 14 return (fetcherConfig: IFetcherConfigExtended): FetcherInterceptRequestReturn<IFetcherConfigExtended> => { 15 ... 16 }; 17}
src/util/create-interceptor-response-fulfilled.ts 范例
1import { 2 FetcherFnInterceptResponseFulfilled 3} from '@alicloud/fetcher'; 4 5import { 6 IFetcherInterceptorConfig, 7 IFetcherConfigExtended 8} from '../types'; 9 10export default function createInterceptorResponseFulfilled(interceptorConfig: IFetcherInterceptorConfig): FetcherFnInterceptResponseFulfilled<IFetcherConfigExtended> { 11 // 在这里消费 interceptorConfig 12 13 return (o: unknown, fetcherConfig: IFetcherConfigExtended): unknown => { 14 ... 15 }; 16}
src/util/create-interceptor-response-rejected.ts 范例
1import { 2 FetcherError, 3 FetcherResponse, 4 FetcherFnInterceptResponseRejected, 5 FetcherFnRequest 6} from '@alicloud/fetcher'; 7 8import { 9 IFetcherInterceptorConfig, 10 IFetcherConfigExtended 11} from '../types'; 12 13export default function createInterceptorResponseRejected(interceptorConfig: IFetcherInterceptorConfig): FetcherFnInterceptResponseRejected<IFetcherConfigExtended> { 14 // 在这里消费 interceptorConfig 15 16 return (err: FetcherError, fetcherConfig: IFetcherConfigExtended, response: FetcherResponse, request: FetcherFnRequest): void => { 17 ... 18 19 throw err; // 如果继续错下去就得 throw 20 }; 21}
src/util/intercept.ts 范例
1import { 2 Fetcher 3} from '@alicloud/fetcher'; 4 5import { 6 IFetcherInterceptorConfig 7} from '../types'; 8 9import createInterceptorRequest from './create-interceptor-request'; 10import createInterceptorResponseFulfilled from './create-interceptor-response-fulfilled'; 11import createInterceptorResponseRejected from './create-interceptor-response-rejected'; 12 13export default function intercept(fetcher: Fetcher, interceptorConfig: IFetcherInterceptorConfig): () => void { 14 return fetcher.interceptRequest(createInterceptorRequest(interceptorConfig)); 15 // 或,任一个可为 undefined 16 return fetcher.interceptResponse(createInterceptorResponseFulfilled(interceptorConfig), createInterceptorResponseRejected(interceptorConfig)); 17}
src/index.ts 范例
1export { default } from './util/intercept'; 2 3export type { 4 IFetcherInterceptorConfig as FetcherInterceptorConfig, 5 IFetcherConfigExtra as FetcherConfigExtra, 6 IFetcherConfigExtended as FetcherConfigExtended 7} from './types';
No vulnerabilities found.
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
0 existing vulnerabilities detected
Reason
no binaries found in the repo
Reason
Found 6/16 approved changesets -- score normalized to 3
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 21 are checked with a SAST tool
Score
3.4
/10
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More