├── dist ├── options.js ├── intercepter.js ├── httpclien-handler.js ├── options.js.map ├── intercepter.js.map ├── profiles │ ├── default-profile.d.ts │ ├── default-profile.js.map │ └── default-profile.js ├── httpclien-handler.js.map ├── httpclien-handler.d.ts ├── task │ ├── task-source.d.ts │ ├── task-source.js.map │ ├── task-source.js │ ├── task.d.ts │ ├── task.js.map │ └── task.js ├── intercepters │ ├── statuscode-intercepter.d.ts │ ├── max-timeout-intercepter.d.ts │ ├── jwt-token-intercepter.d.ts │ ├── retry-intercepter.d.ts │ ├── auto-domain-intercepter.d.ts │ ├── timeout-interceper.d.ts │ ├── statuscode-intercepter.js.map │ ├── statuscode-intercepter.js │ ├── auto-domain-intercepter.js.map │ ├── jwt-token-intercepter.js.map │ ├── max-timeout-intercepter.js.map │ ├── retry-intercepter.js.map │ ├── auto-domain-intercepter.js │ ├── jwt-token-intercepter.js │ ├── max-timeout-intercepter.js │ ├── timeout-interceper.js.map │ ├── retry-intercepter.js │ └── timeout-interceper.js ├── IntercepterCollection.d.ts ├── index.js.map ├── IntercepterCollection.js ├── errors.d.ts ├── IntercepterCollection.js.map ├── index.d.ts ├── index.js ├── url.d.ts ├── handlers │ ├── uni-handler.d.ts │ ├── uni-handler.js.map │ └── uni-handler.js ├── token-storages │ ├── token-storage.d.ts │ ├── token-storage.js.map │ └── token-storage.js ├── intercepter.d.ts ├── cancel-token.d.ts ├── cancel-token.js.map ├── errors.js.map ├── errors.js ├── cancel-token.js ├── options.d.ts ├── httpclient.d.ts ├── url.js.map ├── httpclient.js.map ├── httpclient.js └── url.js ├── demo └── demo │ ├── src │ ├── sfc.d.ts │ ├── static │ │ └── logo.png │ ├── components │ │ ├── Foo.vue │ │ ├── demo2.vue │ │ ├── demo1.vue │ │ ├── demo4.vue │ │ └── demo3.vue │ ├── pages.json │ ├── App.vue │ ├── main.ts │ ├── pages │ │ └── index │ │ │ └── index.vue │ ├── uni.scss │ ├── intercepter.ts │ └── manifest.json │ ├── .yarnrc │ ├── .gitignore │ ├── README.md │ ├── postcss.config.js │ ├── tsconfig.json │ ├── public │ └── index.html │ ├── babel.config.js │ └── package.json ├── tslint.json ├── .editorconfig ├── src ├── httpclien-handler.ts ├── profiles │ └── default-profile.ts ├── task │ ├── task-source.ts │ └── task.ts ├── index.ts ├── IntercepterCollection.ts ├── intercepter.ts ├── intercepters │ ├── statuscode-intercepter.ts │ ├── auto-domain-intercepter.ts │ ├── max-timeout-intercepter.ts │ ├── jwt-token-intercepter.ts │ ├── retry-intercepter.ts │ └── timeout-interceper.ts ├── errors.ts ├── options.ts ├── token-storages │ └── token-storage.ts ├── cancel-token.ts ├── handlers │ └── uni-handler.ts └── url.ts ├── package.json ├── postcss.config.js ├── tsconfig.json ├── LICENSE ├── babel.config.js ├── .gitattributes ├── .gitignore ├── README.md └── yarn.lock /dist/options.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | //# sourceMappingURL=options.js.map -------------------------------------------------------------------------------- /dist/intercepter.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | //# sourceMappingURL=intercepter.js.map -------------------------------------------------------------------------------- /dist/httpclien-handler.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | //# sourceMappingURL=httpclien-handler.js.map -------------------------------------------------------------------------------- /demo/demo/src/sfc.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from 'vue' 3 | export default Vue 4 | } -------------------------------------------------------------------------------- /demo/demo/src/static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John0King/uni-HttpClient/HEAD/demo/demo/src/static/logo.png -------------------------------------------------------------------------------- /dist/options.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/intercepter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"intercepter.js","sourceRoot":"","sources":["../src/intercepter.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules":{ 3 | "tslint.enable":false, 4 | "typescript.validate.enable": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = crlf 3 | charset = utf-8 4 | indent_size = 4 5 | indent_style = space 6 | insert_final_newline = true 7 | -------------------------------------------------------------------------------- /dist/profiles/default-profile.d.ts: -------------------------------------------------------------------------------- 1 | import type { HandlerProfiles } from "../options"; 2 | export declare let defaultProfile: HandlerProfiles; 3 | -------------------------------------------------------------------------------- /dist/httpclien-handler.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"httpclien-handler.js","sourceRoot":"","sources":["../src/httpclien-handler.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /demo/demo/.yarnrc: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | yarn-path ".yarn/releases/yarn-1.22.10.cjs" 6 | -------------------------------------------------------------------------------- /demo/demo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | unpackage/ 4 | dist/ 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .project 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw* 24 | -------------------------------------------------------------------------------- /dist/httpclien-handler.d.ts: -------------------------------------------------------------------------------- 1 | import type { IntercepterRequestContext, IntercepterResponseContext } from "./intercepter"; 2 | import type { HttpClient } from './httpclient'; 3 | /** 4 | * httpclient 处理终端的接口 5 | */ 6 | export interface IHttpClientHandler { 7 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise; 8 | } 9 | -------------------------------------------------------------------------------- /dist/profiles/default-profile.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"default-profile.js","sourceRoot":"","sources":["../../src/profiles/default-profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,2BAA2B,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAGhI,MAAM,CAAC,IAAI,cAAc,GAAoB;IACzC,OAAO,EAAE,IAAI,2BAA2B,EAAE;IAC1C,MAAM,EAAE,IAAI,0BAA0B,EAAE;IACxC,QAAQ,EAAE,IAAI,4BAA4B,EAAE;CAC/C,CAAA"} -------------------------------------------------------------------------------- /demo/demo/README.md: -------------------------------------------------------------------------------- 1 | # demo 2 | 3 | 需要把 package.json 中 uni-httpclient 修改成npm上的版本号 (建议使用 yarn) 4 | 然后 5 | ``` 6 | npm install 7 | //或者 8 | yarn 9 | ``` 10 | 11 | ``` 12 | npm run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | ``` 17 | npm run build 18 | ``` 19 | 20 | ### Customize configuration 21 | See [Configuration Reference](https://cli.vuejs.org/config/). 22 | -------------------------------------------------------------------------------- /dist/profiles/default-profile.js: -------------------------------------------------------------------------------- 1 | import { UniDownloadHttpClientHandler, UniRequestHttpClientHandler, UniUploadHttpClientHandler } from "../handlers/uni-handler"; 2 | export let defaultProfile = { 3 | request: new UniRequestHttpClientHandler(), 4 | upload: new UniUploadHttpClientHandler(), 5 | download: new UniDownloadHttpClientHandler() 6 | }; 7 | //# sourceMappingURL=default-profile.js.map -------------------------------------------------------------------------------- /src/httpclien-handler.ts: -------------------------------------------------------------------------------- 1 | import type { IntercepterRequestContext, IntercepterResponseContext } from "./intercepter"; 2 | import type { HttpClient } from './httpclient'; 3 | 4 | /** 5 | * httpclient 处理终端的接口 6 | */ 7 | export interface IHttpClientHandler { 8 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise; 9 | } 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /dist/task/task-source.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 更优雅的方式设置Promise, (解决Promise 的设计存在问题,无法从外部设置值) 3 | * 4 | */ 5 | export declare class TaskSource { 6 | private resolve; 7 | private reject; 8 | constructor(); 9 | readonly task: Promise; 10 | setResult(value: T): void; 11 | setError(reason?: any): void; 12 | startAction(action: (task: TaskSource) => any): void; 13 | } 14 | -------------------------------------------------------------------------------- /demo/demo/src/components/Foo.vue: -------------------------------------------------------------------------------- 1 | 7 | 17 | -------------------------------------------------------------------------------- /src/profiles/default-profile.ts: -------------------------------------------------------------------------------- 1 | import { UniDownloadHttpClientHandler, UniRequestHttpClientHandler, UniUploadHttpClientHandler } from "../handlers/uni-handler"; 2 | import type { HandlerProfiles } from "../options"; 3 | 4 | export let defaultProfile :HandlerProfiles = { 5 | request: new UniRequestHttpClientHandler(), 6 | upload: new UniUploadHttpClientHandler(), 7 | download: new UniDownloadHttpClientHandler() 8 | } 9 | -------------------------------------------------------------------------------- /dist/intercepters/statuscode-intercepter.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterResponseContext, IntercepterDelegate } from '../intercepter'; 2 | /** 3 | * 如果添加该拦截器, 任何状态码不在200~ 400 之间的状态码将 抛出 @see StatusCodeError 4 | */ 5 | export declare class StatusCodeIntercepter implements HttpClientIntercepter { 6 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 7 | } 8 | -------------------------------------------------------------------------------- /dist/intercepters/max-timeout-intercepter.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterDelegate, IntercepterRequestContext, IntercepterResponseContext } from '../intercepter'; 2 | export declare class MaxTimeoutIntercepter implements HttpClientIntercepter { 3 | maxTimeoutSeconds: number; 4 | constructor(maxTimeoutSeconds?: number); 5 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /dist/IntercepterCollection.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter } from "./intercepter"; 2 | export declare class IntercepterCollection extends Array { 3 | insertBefore(type: Type, value: HttpClientIntercepter): void; 4 | insertAfter(type: Type, value: HttpClientIntercepter): void; 5 | } 6 | interface Type { 7 | new (...args: any[]): T; 8 | } 9 | export {}; 10 | -------------------------------------------------------------------------------- /dist/intercepters/jwt-token-intercepter.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterResponseContext, IntercepterDelegate } from "../intercepter"; 2 | export declare class JwtTokenIntercepter implements HttpClientIntercepter { 3 | private tokenFactory; 4 | constructor(tokenFactory: (url: string) => string | null | Promise); 5 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 6 | } 7 | -------------------------------------------------------------------------------- /dist/intercepters/retry-intercepter.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterDelegate, IntercepterRequestContext, IntercepterResponseContext } from '../intercepter'; 2 | /** 3 | * 重试拦截器 4 | */ 5 | export declare class RetryIntercepter implements HttpClientIntercepter { 6 | defaultRetrycount: number; 7 | defaultRetryDelay: number; 8 | constructor(defaultRetrycount?: number, defaultRetryDelay?: number); 9 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /dist/intercepters/auto-domain-intercepter.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterResponseContext, IntercepterDelegate } from "../intercepter"; 2 | export declare class AutoDomainIntercepter implements HttpClientIntercepter { 3 | factory: (url: string) => string; 4 | /** 5 | * 6 | * @param factory return a baseurl, not full url 7 | */ 8 | constructor(factory: (url: string) => string); 9 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /demo/demo/src/pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages 3 | { 4 | "path": "pages/index/index", 5 | "style": { 6 | "navigationBarTitleText": "uni-app" 7 | } 8 | } 9 | ], 10 | "globalStyle": { 11 | "navigationBarTextStyle": "black", 12 | "navigationBarTitleText": "uni-app", 13 | "navigationBarBackgroundColor": "#F8F8F8", 14 | "backgroundColor": "#F8F8F8", 15 | "rpxCalcMaxDeviceWidth":99999, 16 | "rpxCalcBaseDeviceWidth":750, 17 | "rpxCalcIncludeWidth":750 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uni-httpclient", 3 | "version": "1.5.1", 4 | "private": false, 5 | "files": [ 6 | "dist" 7 | ], 8 | "main": "./dist/index.js", 9 | "types": "./dist/index.d.ts", 10 | "author": "john0king", 11 | "scripts": { 12 | "build": "tsc", 13 | "pack": "yarn run build && yarn pack" 14 | }, 15 | "repository": "https://github.com/John0King/uni-HttpClient", 16 | "license": "MIT", 17 | "dependencies": {}, 18 | "devDependencies": { 19 | "@dcloudio/types": "3.4.19", 20 | "typescript": "^5.9.2", 21 | "vue": "^3.5.18" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dist/intercepters/timeout-interceper.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterDelegate, IntercepterResponseContext } from '../intercepter'; 2 | export declare class TimeoutIntercepter implements HttpClientIntercepter { 3 | cancelAfterSeconds?: number | undefined; 4 | private readonly _key; 5 | /** 6 | * 支持超时的拦截器 7 | * @param cancelAfterSeconds 全局超时秒数 8 | */ 9 | constructor(cancelAfterSeconds?: number | undefined); 10 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 11 | } 12 | -------------------------------------------------------------------------------- /dist/task/task-source.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"task-source.js","sourceRoot":"","sources":["../../src/task/task-source.ts"],"names":[],"mappings":"AACA;;;GAGG;AACH,MAAM,OAAO,UAAU;IAMnB;QACI,IAAI,CAAC,IAAI,GAAG,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACzB,CAAC,CAAC,CAAA;IACN,CAAC;IAID,SAAS,CAAC,KAAQ;QACd,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,QAAQ,CAAC,MAAY;QACjB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAED,WAAW,CAAC,MAA6B;QACrC,IAAG;YACC,MAAM,CAAC,IAAI,CAAC,CAAC;SAChB;QACD,OAAM,CAAC,EAAC;YACJ,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;SACpB;IACL,CAAC;CAEJ"} -------------------------------------------------------------------------------- /demo/demo/src/App.vue: -------------------------------------------------------------------------------- 1 | 16 | 26 | -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEtD,cAAc,WAAW,CAAC;AAE1B,cAAc,eAAe,CAAC;AAE9B,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAE/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAE9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEpE,cAAc,qBAAqB,CAAC;AAEpC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,gBAAgB,CAAA;AAE9B,cAAc,UAAU,CAAC;AAEzB,cAAc,gCAAgC,CAAA;AAE9C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC"} -------------------------------------------------------------------------------- /dist/task/task-source.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 更优雅的方式设置Promise, (解决Promise 的设计存在问题,无法从外部设置值) 3 | * 4 | */ 5 | export class TaskSource { 6 | constructor() { 7 | this.task = new Promise((resolve, reject) => { 8 | this.resolve = resolve; 9 | this.reject = reject; 10 | }); 11 | } 12 | setResult(value) { 13 | this.resolve(value); 14 | } 15 | setError(reason) { 16 | this.reject(reason); 17 | } 18 | startAction(action) { 19 | try { 20 | action(this); 21 | } 22 | catch (e) { 23 | this.setError(e); 24 | } 25 | } 26 | } 27 | //# sourceMappingURL=task-source.js.map -------------------------------------------------------------------------------- /dist/IntercepterCollection.js: -------------------------------------------------------------------------------- 1 | export class IntercepterCollection extends Array { 2 | insertBefore(type, value) { 3 | let index = this.findIndex(x => x instanceof type); 4 | if (index > 0) { 5 | this.splice(index, 0, value); 6 | } 7 | else { 8 | this.unshift(value); 9 | } 10 | } 11 | insertAfter(type, value) { 12 | let index = this.findIndex(x => x instanceof type); 13 | if (index >= 0) { 14 | index = index + 1; 15 | this.splice(index, 0, value); 16 | } 17 | else { 18 | this.push(value); 19 | } 20 | } 21 | } 22 | //# sourceMappingURL=IntercepterCollection.js.map -------------------------------------------------------------------------------- /dist/task/task.d.ts: -------------------------------------------------------------------------------- 1 | import type { ICancelToken } from '../cancel-token'; 2 | export declare class Task { 3 | /** 4 | * 延时一段时间 5 | * @param ms 延时的时间 单位毫秒 6 | * @param cancelToken 取消令牌 7 | */ 8 | static delay(ms: number, cancelToken?: ICancelToken): Promise; 9 | /** 10 | * 等待其中一个@see Promise 完成 11 | * @param tasks 一个promise 数组 12 | */ 13 | static whenAny(tasks: Promise[]): Promise>; 14 | /** 15 | * 等待所有的promise完成 16 | * @param tasks 一个promise 数组 17 | */ 18 | static whenAll(tasks: Promise[]): Promise; 19 | static fromReult(data: T): Promise; 20 | static fromError(error: Error | any): Promise; 21 | } 22 | -------------------------------------------------------------------------------- /dist/errors.d.ts: -------------------------------------------------------------------------------- 1 | import type { ResponseData } from './options'; 2 | /** 3 | * 状态码错误 4 | */ 5 | export declare class StatusCodeError extends Error { 6 | statusCode: number; 7 | respose?: ResponseData | undefined; 8 | private __proto__; 9 | constructor(statusCode: number, respose?: ResponseData | undefined); 10 | static messageMap: { 11 | [key: number]: { 12 | label: string; 13 | display?: string; 14 | }; 15 | }; 16 | static getMessage(statusCode: number): string; 17 | getDisplayMessage(): string; 18 | } 19 | export declare class CancelError extends Error { 20 | private __proto__; 21 | constructor(message?: string); 22 | isCancelError: boolean; 23 | } 24 | -------------------------------------------------------------------------------- /dist/IntercepterCollection.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"IntercepterCollection.js","sourceRoot":"","sources":["../src/IntercepterCollection.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,qBAAsB,SAAQ,KAA4B;IACnE,YAAY,CAAkC,IAAY,EAAE,KAA2B;QACnF,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA,EAAE,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;QAClD,IAAG,KAAK,GAAG,CAAC,EAAC;YACT,IAAI,CAAC,MAAM,CAAC,KAAK,EAAC,CAAC,EAAC,KAAK,CAAC,CAAC;SAC9B;aACG;YACA,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;SACvB;IAEL,CAAC;IAED,WAAW,CAAkC,IAAY,EAAE,KAA2B;QAClF,IAAI,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA,EAAE,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;QAClD,IAAG,KAAK,IAAI,CAAC,EAAC;YACV,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC;YAClB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAC,CAAC,EAAC,KAAK,CAAC,CAAC;SAC9B;aACG;YACA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;SACpB;IACL,CAAC;CACJ"} -------------------------------------------------------------------------------- /demo/demo/src/main.ts: -------------------------------------------------------------------------------- 1 | import { httpClient, StatusCodeIntercepter } from 'uni-httpclient' 2 | import Vue from 'vue' 3 | import App from './App.vue' 4 | import { GlobalErrorIntercepter, MyAuthIntercepter } from './intercepter' 5 | 6 | Vue.config.productionTip = false 7 | // 我们推荐使用实例, 我们已经移除掉全局拦截器, 8 | // 您可以创建其他的 HttpClient 实例,并添加不同的拦截器 9 | // 这将让您可以对不同的 api 使用不用 HttpClient 成为肯能 10 | httpClient.setupDefaults({ 11 | timeout:15, 12 | maxTimeout:9, 13 | retryCount:3, 14 | retryDelay:1000, 15 | statusCodeError:true, 16 | baseUrl:"http://localhost:500/api/" 17 | }) 18 | // 在下面配置拦截器, 比如放上 Jwt拦截器 19 | // 或者自己全局拦截所有的错误代码 拦截器 20 | httpClient.intercepters.insertBefore(StatusCodeIntercepter,new MyAuthIntercepter()) 21 | httpClient.intercepters.unshift(new GlobalErrorIntercepter()) 22 | 23 | new App().$mount() 24 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | module.exports = { 3 | parser: require('postcss-comment'), 4 | plugins: [ 5 | require('postcss-import')({ 6 | resolve (id, basedir, importOptions) { 7 | if (id.startsWith('~@/')) { 8 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) 9 | } else if (id.startsWith('@/')) { 10 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) 11 | } else if (id.startsWith('/') && !id.startsWith('//')) { 12 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) 13 | } 14 | return id 15 | } 16 | }), 17 | require('autoprefixer')({ 18 | remove: process.env.UNI_PLATFORM !== 'h5' 19 | }), 20 | require('@dcloudio/vue-cli-plugin-uni/packages/postcss') 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /demo/demo/postcss.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | module.exports = { 3 | parser: require('postcss-comment'), 4 | plugins: [ 5 | require('postcss-import')({ 6 | resolve (id, basedir, importOptions) { 7 | if (id.startsWith('~@/')) { 8 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) 9 | } else if (id.startsWith('@/')) { 10 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) 11 | } else if (id.startsWith('/') && !id.startsWith('//')) { 12 | return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) 13 | } 14 | return id 15 | } 16 | }), 17 | require('autoprefixer')({ 18 | remove: process.env.UNI_PLATFORM !== 'h5' 19 | }), 20 | require('@dcloudio/vue-cli-plugin-uni/packages/postcss') 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | export { HttpClient, httpClient } from "./httpclient"; 2 | export * from "./options"; 3 | export * from "./intercepter"; 4 | export { JwtTokenIntercepter } from "./intercepters/jwt-token-intercepter"; 5 | export { AutoDomainIntercepter } from "./intercepters/auto-domain-intercepter"; 6 | export { StatusCodeIntercepter } from "./intercepters/statuscode-intercepter"; 7 | export { TimeoutIntercepter } from "./intercepters/timeout-interceper"; 8 | export { RetryIntercepter } from "./intercepters/retry-intercepter"; 9 | export * from "./httpclien-handler"; 10 | export * from "./handlers/uni-handler"; 11 | export * from "./cancel-token"; 12 | export * from "./errors"; 13 | export * from "./token-storages/token-storage"; 14 | export { Task } from "./task/task"; 15 | export { TaskSource } from "./task/task-source"; 16 | export { Url } from "./url"; 17 | -------------------------------------------------------------------------------- /src/task/task-source.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * 更优雅的方式设置Promise, (解决Promise 的设计存在问题,无法从外部设置值) 4 | * 5 | */ 6 | export class TaskSource{ 7 | 8 | private resolve!: (value: T) => void; 9 | private reject!: (reason?: any) => void; 10 | 11 | 12 | constructor() { 13 | this.task = new Promise((resolve, reject) => { 14 | this.resolve = resolve; 15 | this.reject = reject; 16 | }) 17 | } 18 | 19 | readonly task: Promise; 20 | 21 | setResult(value: T) { 22 | this.resolve(value); 23 | } 24 | 25 | setError(reason?: any) { 26 | this.reject(reason); 27 | } 28 | 29 | startAction(action:(task:TaskSource)=>any){ 30 | try{ 31 | action(this); 32 | } 33 | catch(e){ 34 | this.setError(e); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | export { HttpClient, httpClient } from "./httpclient"; 2 | export * from "./options"; 3 | export * from "./intercepter"; 4 | export { JwtTokenIntercepter } from "./intercepters/jwt-token-intercepter"; 5 | export { AutoDomainIntercepter } from "./intercepters/auto-domain-intercepter"; 6 | export { StatusCodeIntercepter } from "./intercepters/statuscode-intercepter"; 7 | export { TimeoutIntercepter } from "./intercepters/timeout-interceper"; 8 | export { RetryIntercepter } from "./intercepters/retry-intercepter"; 9 | export * from "./httpclien-handler"; 10 | export * from "./handlers/uni-handler"; 11 | export * from "./cancel-token"; 12 | export * from "./errors"; 13 | export * from "./token-storages/token-storage"; 14 | export { Task } from "./task/task"; 15 | export { TaskSource } from "./task/task-source"; 16 | export { Url } from "./url"; 17 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /demo/demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "esModuleInterop": true, 10 | "allowSyntheticDefaultImports": true, 11 | "experimentalDecorators":true, 12 | "sourceMap": true, 13 | "skipLibCheck": true, 14 | "baseUrl": ".", 15 | "types": [ 16 | "webpack-env", 17 | "@dcloudio/types", 18 | "miniprogram-api-typings", 19 | "mini-types" 20 | ], 21 | "paths": { 22 | "@/*": [ 23 | "./src/*" 24 | ] 25 | }, 26 | "lib": [ 27 | "esnext", 28 | "dom", 29 | "dom.iterable", 30 | "scripthost" 31 | ] 32 | }, 33 | "exclude": [ 34 | "node_modules", 35 | "unpackage", 36 | "src/**/*.nvue" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { HttpClient, httpClient } from "./httpclient"; 2 | 3 | export * from "./options"; 4 | 5 | export * from "./intercepter"; 6 | 7 | export { JwtTokenIntercepter } from "./intercepters/jwt-token-intercepter"; 8 | 9 | export { AutoDomainIntercepter } from "./intercepters/auto-domain-intercepter"; 10 | 11 | export { StatusCodeIntercepter } from "./intercepters/statuscode-intercepter"; 12 | 13 | export { TimeoutIntercepter } from "./intercepters/timeout-interceper"; 14 | 15 | export { RetryIntercepter } from "./intercepters/retry-intercepter"; 16 | 17 | export * from "./httpclien-handler"; 18 | 19 | export * from "./handlers/uni-handler"; 20 | 21 | export * from "./cancel-token" 22 | 23 | export * from "./errors"; 24 | 25 | export * from "./token-storages/token-storage" 26 | 27 | export { Task } from "./task/task"; 28 | export { TaskSource } from "./task/task-source"; 29 | export { Url } from "./url"; 30 | -------------------------------------------------------------------------------- /dist/url.d.ts: -------------------------------------------------------------------------------- 1 | export declare class Url { 2 | #private; 3 | constructor(url?: string); 4 | /** `http` or `https` */ 5 | scheme?: string; 6 | domain?: string | null; 7 | port?: number | null; 8 | /** domain + port */ 9 | get host(): string | null; 10 | set host(h: string | null); 11 | get pathAndQuery(): string | null; 12 | set pathAndQuery(value: string | null); 13 | get path(): string | null; 14 | set path(path: string | null); 15 | get queryString(): string | null; 16 | set queryString(v: string | null); 17 | query?: Record | null; 18 | get hasQuery(): boolean; 19 | get isAbsolute(): boolean; 20 | get isEmpty(): boolean; 21 | get isQuery(): boolean; 22 | toString(): string; 23 | private parsePathAndQuery; 24 | private parseQuery; 25 | /** return a new Url */ 26 | add(url: Url): Url; 27 | clone(): Url; 28 | } 29 | -------------------------------------------------------------------------------- /dist/handlers/uni-handler.d.ts: -------------------------------------------------------------------------------- 1 | import type { IntercepterRequestContext, IntercepterResponseContext } from "../intercepter"; 2 | import type { HttpClient } from '../httpclient'; 3 | import type { IHttpClientHandler } from "../httpclien-handler"; 4 | /** uni 的 GET POST PUT OPTION 等操作的 处理终端 */ 5 | export declare class UniRequestHttpClientHandler implements IHttpClientHandler { 6 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise; 7 | } 8 | /** uni 的 上传文件 操作的 处理终端 */ 9 | export declare class UniUploadHttpClientHandler implements IHttpClientHandler { 10 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise; 11 | } 12 | /** uni 的 下载文件 操作的 处理终端 */ 13 | export declare class UniDownloadHttpClientHandler implements IHttpClientHandler { 14 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise; 15 | } 16 | -------------------------------------------------------------------------------- /src/IntercepterCollection.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter } from "./intercepter"; 2 | 3 | export class IntercepterCollection extends Array{ 4 | insertBefore(type:Type, value:HttpClientIntercepter):void{ 5 | let index = this.findIndex(x=> x instanceof type); 6 | if(index > 0){ 7 | this.splice(index,0,value); 8 | } 9 | else{ 10 | this.unshift(value); 11 | } 12 | 13 | } 14 | 15 | insertAfter(type:Type, value:HttpClientIntercepter):void{ 16 | let index = this.findIndex(x=> x instanceof type); 17 | if(index >= 0){ 18 | index = index + 1; 19 | this.splice(index,0,value); 20 | } 21 | else{ 22 | this.push(value); 23 | } 24 | } 25 | } 26 | 27 | interface Type{ 28 | new (...args:any[]):T 29 | } 30 | -------------------------------------------------------------------------------- /dist/token-storages/token-storage.d.ts: -------------------------------------------------------------------------------- 1 | export declare class TokenStorage { 2 | private tokenType; 3 | constructor(tokenType: string); 4 | expireOffsetMs: number; 5 | private readonly cChar; 6 | private readonly akey; 7 | private getKey; 8 | isTokenExpired(domain: string): boolean; 9 | getToken(domain: string, includeExpired?: boolean): string | null; 10 | /** 11 | * async 允许你挂载 onTokenExpired 钩子函数 12 | */ 13 | getTokenAsync(domain: string): Promise; 14 | /** 15 | * 设置token 16 | * @param domain 域名, 你可以设置 '*' 但不能是null 17 | * @param expireIn 秒 18 | */ 19 | setToken(domain: string, token: string, expireIn: number): void; 20 | clearToken(domain: string): void; 21 | onTokenExpired?: (storage: TokenStorage, domain: string) => Promise; 22 | } 23 | export declare const tokenStorage: TokenStorage; 24 | export declare const freshTokenStorage: TokenStorage; 25 | -------------------------------------------------------------------------------- /dist/intercepters/statuscode-intercepter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"statuscode-intercepter.js","sourceRoot":"","sources":["../../src/intercepters/statuscode-intercepter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAEzD;;GAEG;AACH,MAAM,OAAO,qBAAqB;IAC9B,MAAM,CAAC,OAAkC,EAAE,IAAyB;;QAChE,IAAG,MAAA,OAAO,CAAC,WAAW,0CAAE,WAAW,EAAC;YAChC,IAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,UAAU,EAAC;gBAC1C,OAAO,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAC,MAAM,EAAC,EAAE;oBAC7D,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAA;aACL;SACJ;QACD,IAAG,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,iBAAiB,KAAI,IAAI,EAAC;YAC9C,OAAO,IAAI,CAAC,OAAO,CAAC;iBACnB,IAAI,CAAC,GAAG,CAAC,EAAE;gBACR,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,GAAG,GAAG,EAAE;oBAC/C,OAAO,GAAG,CAAC;iBACd;qBACI;oBACD,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;iBACjD;YACL,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAA,CAAC,CAAC,CAAC,CAAC;SAC5B;aACG;YACA,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;SACxB;IAEL,CAAC;CAGJ"} -------------------------------------------------------------------------------- /dist/intercepter.d.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClient } from './httpclient'; 2 | import type { PipeOptions, HttpMethods } from "./options"; 3 | import type { IHttpClientHandler } from './httpclien-handler'; 4 | export interface HttpClientIntercepter { 5 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise; 6 | } 7 | export interface IntercepterRequestContext { 8 | url: string; 9 | readonly method: HttpMethods; 10 | header?: any; 11 | data?: any; 12 | responseType?: "text" | "arraybuffer"; 13 | pipeOptions: PipeOptions; 14 | } 15 | export interface IntercepterResponseContext { 16 | httpClient?: HttpClient; 17 | httpClientHander?: IHttpClientHandler; 18 | statusCode: number; 19 | data: any; 20 | error?: any; 21 | header: any; 22 | pipeOptions: PipeOptions; 23 | } 24 | export interface IntercepterDelegate { 25 | (request: IntercepterRequestContext): Promise; 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2017", 4 | "module": "ESNext", 5 | "outDir": "dist", 6 | "declaration": true, 7 | "strict": true, 8 | "jsx": "preserve", 9 | "importHelpers": false, 10 | //"noEmitHelpers": false, 11 | "moduleResolution": "node", 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "experimentalDecorators":true, 15 | "sourceMap": true, 16 | "baseUrl": ".", 17 | "skipLibCheck": true, 18 | "verbatimModuleSyntax":true, 19 | "types": [ 20 | //"webpack-env", 21 | "@dcloudio/types/uni-app" 22 | ], 23 | "paths": { 24 | // "@/*": [ 25 | // "./src/*" 26 | // ] 27 | }, 28 | "lib": [ 29 | "esnext", 30 | "dom", 31 | // "dom.iterable", 32 | "scripthost" 33 | ] 34 | }, 35 | "exclude": [ 36 | "node_modules", 37 | "unpackage", 38 | "src/**/*.nvue", 39 | "dist", 40 | "demo" 41 | ], 42 | "compileOnSave": true 43 | } 44 | -------------------------------------------------------------------------------- /src/intercepter.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClient } from './httpclient'; 2 | import type { PipeOptions, HttpMethods } from "./options"; 3 | import type { IHttpClientHandler } from './httpclien-handler'; 4 | 5 | export interface HttpClientIntercepter { 6 | handle( 7 | request: IntercepterRequestContext, 8 | next: IntercepterDelegate 9 | ): Promise; 10 | } 11 | 12 | export interface IntercepterRequestContext { 13 | url: string; 14 | readonly method:HttpMethods; 15 | header?: any; 16 | data?: any; 17 | responseType?: "text" | "arraybuffer"; 18 | pipeOptions:PipeOptions 19 | } 20 | 21 | export interface IntercepterResponseContext { 22 | httpClient?: HttpClient; 23 | httpClientHander?:IHttpClientHandler; 24 | statusCode: number; 25 | data: any; 26 | error?: any; 27 | header: any; 28 | pipeOptions:PipeOptions 29 | } 30 | 31 | export interface IntercepterDelegate{ 32 | (request: IntercepterRequestContext): Promise 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 john0king 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/demo/src/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 35 | 36 | 40 | -------------------------------------------------------------------------------- /dist/cancel-token.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * a CancelToken that support safe cancellation 3 | */ 4 | export declare class CancelToken implements ICancelSource, ICancelToken { 5 | constructor(); 6 | constructor(token: CancelToken); 7 | constructor(token: ICancelToken); 8 | constructor(afterms: number); 9 | isCanceled: boolean; 10 | throwIfCanceled(): void; 11 | linkToken(token: CancelToken): void; 12 | linkToken(token: ICancelToken): void; 13 | private _t?; 14 | cancelAfter(timems: number): this; 15 | stopCancel(): this; 16 | cancel(): void; 17 | private _actions; 18 | private triggerAction; 19 | register(action: (sender: CancelToken) => any): this; 20 | getToken(): CancelToken; 21 | } 22 | export interface ICancelSource { 23 | cancelAfter(timems: number): ICancelSource; 24 | cancel(): void; 25 | stopCancel(): ICancelSource; 26 | linkToken(token: ICancelToken): void; 27 | getToken(): ICancelToken; 28 | } 29 | export interface ICancelToken { 30 | isCanceled: boolean; 31 | throwIfCanceled(): void; 32 | register(action: (sender: ICancelToken) => any): ICancelToken; 33 | } 34 | -------------------------------------------------------------------------------- /dist/intercepters/statuscode-intercepter.js: -------------------------------------------------------------------------------- 1 | import { StatusCodeError, CancelError } from '../errors'; 2 | /** 3 | * 如果添加该拦截器, 任何状态码不在200~ 400 之间的状态码将 抛出 @see StatusCodeError 4 | */ 5 | export class StatusCodeIntercepter { 6 | handle(request, next) { 7 | var _a, _b; 8 | if ((_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) { 9 | if (request.pipeOptions.cancelToken.isCanceled) { 10 | return new Promise((resolve, reject) => { 11 | reject(new CancelError()); 12 | }); 13 | } 14 | } 15 | if (((_b = request.pipeOptions) === null || _b === void 0 ? void 0 : _b.preventStatusCode) != true) { 16 | return next(request) 17 | .then(res => { 18 | if (res.statusCode >= 200 && res.statusCode < 400) { 19 | return res; 20 | } 21 | else { 22 | throw new StatusCodeError(res.statusCode, res); 23 | } 24 | }) 25 | .catch(e => { throw e; }); 26 | } 27 | else { 28 | return next(request); 29 | } 30 | } 31 | } 32 | //# sourceMappingURL=statuscode-intercepter.js.map -------------------------------------------------------------------------------- /demo/demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 17 | 18 | 19 | 20 | 21 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /dist/intercepters/auto-domain-intercepter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"auto-domain-intercepter.js","sourceRoot":"","sources":["../../src/intercepters/auto-domain-intercepter.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,MAAM,OAAO,qBAAqB;IAC9B;;;OAGG;IACH,YAAmB,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;IAAI,CAAC;IAExD,MAAM,CAAC,OAAkC,EAAE,IAAyB;;QAChE,IAAG,MAAA,OAAO,CAAC,WAAW,0CAAE,WAAW,EAAC;YAChC,IAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,UAAU,EAAC;gBAC1C,OAAO,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAC,MAAM,EAAC,EAAE;oBAC7D,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAA;aACL;SACJ;QACD,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,iBAAiB,KAAI,IAAI,EAAE;YAEhD,IACI,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC;gBAChD,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EACnD;gBACE,+CAA+C;gBAC/C,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE;oBACvB,OAAO,CAAC,GAAG,GAAG,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;iBACnC;gBACD,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACxC,IAAI,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE;oBAClD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;iBACnD;gBACD,OAAO,CAAC,GAAG,GAAG,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC;aACvC;YAED,qEAAqE;SACxE;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;CACJ"} -------------------------------------------------------------------------------- /demo/demo/src/components/demo2.vue: -------------------------------------------------------------------------------- 1 | 9 | 35 | 36 | 48 | -------------------------------------------------------------------------------- /src/intercepters/statuscode-intercepter.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterResponseContext, IntercepterDelegate } from '../intercepter'; 2 | import { StatusCodeError, CancelError } from '../errors'; 3 | 4 | /** 5 | * 如果添加该拦截器, 任何状态码不在200~ 400 之间的状态码将 抛出 @see StatusCodeError 6 | */ 7 | export class StatusCodeIntercepter implements HttpClientIntercepter { 8 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 9 | if(request.pipeOptions?.cancelToken){ 10 | if(request.pipeOptions.cancelToken.isCanceled){ 11 | return new Promise((resolve,reject)=>{ 12 | reject(new CancelError()); 13 | }) 14 | } 15 | } 16 | if(request.pipeOptions?.preventStatusCode != true){ 17 | return next(request) 18 | .then(res => { 19 | if (res.statusCode >= 200 && res.statusCode < 400) { 20 | return res; 21 | } 22 | else { 23 | throw new StatusCodeError(res.statusCode, res) 24 | } 25 | }) 26 | .catch(e => { throw e }); 27 | } 28 | else{ 29 | return next(request); 30 | } 31 | 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /dist/intercepters/jwt-token-intercepter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"jwt-token-intercepter.js","sourceRoot":"","sources":["../../src/intercepters/jwt-token-intercepter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,MAAM,OAAO,GAAG,eAAe,CAAC;AAChC,MAAM,OAAO,mBAAmB;IAE5B,YAAoB,YAA8D;QAA9D,iBAAY,GAAZ,YAAY,CAAkD;IAElF,CAAC;IAED,MAAM,CAAC,OAAkC,EAAE,IAAyB;;QAChE,IAAG,MAAA,OAAO,CAAC,WAAW,0CAAE,WAAW,EAAC;YAChC,IAAG,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,UAAU,EAAC;gBAC1C,OAAO,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAC,MAAM,EAAC,EAAE;oBAC7D,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAA;aACL;SACJ;QACD,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,eAAe,KAAI,IAAI,EAAE;YAC9C,wCAAwC;YACxC,OAAO,CAAC,MAAM,GAAG,MAAA,OAAO,CAAC,MAAM,mCAAI,EAAE,CAAC;YACtC,sEAAsE;YACtE,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;gBAClC,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aAClC;iBACI,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,SAAS,EAAE;gBAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBAC7C,qBAAqB;gBACrB,IAAI,KAAK,YAAY,OAAO,EAAC;oBACzB,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAA,EAAE;wBACjB,IAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,EAAC;4BACpB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,EAAE,CAAA;yBAC1C;oBACL,CAAC,CAAC,CAAC,IAAI,CAAC,GAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;iBAC/B;qBACI,IAAI,KAAK,IAAI,IAAI,EAAE;oBACpB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,UAAU,KAAK,EAAE,CAAA;iBAC9C;aAEJ;SACJ;QAGD,qEAAqE;QACrE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;IAEzB,CAAC;CAGJ"} -------------------------------------------------------------------------------- /dist/intercepters/max-timeout-intercepter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"max-timeout-intercepter.js","sourceRoot":"","sources":["../../src/intercepters/max-timeout-intercepter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAGpC,MAAM,OAAO,qBAAqB;IAE9B,YAAmB,oBAA2B,EAAE;QAA7B,sBAAiB,GAAjB,iBAAiB,CAAY;IAEhD,CAAC;IAED,MAAM,CAAC,OAAkC,EAAE,IAAyB;;QAChE,IAAG,MAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,WAAW,0CAAE,WAAW,0CAAE,UAAU,EAAC;YAC7C,OAAO,IAAI,CAAC,SAAS,CAA6B,IAAI,WAAW,EAAE,CAAC,CAAA;SACvE;QAED,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,cAAc,KAAI,IAAI,EAAE;YAC7C,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,IAAI,IAAI,CAAC,iBAAiB,GAAG,CAAC,EAAE;gBAC9D,IAAI,OAAO,CAAC,WAAW,IAAI,IAAI,EAAE;oBAC7B,OAAO,CAAC,WAAW,GAAG,EAAE,CAAC;iBAC5B;gBACD,OAAO,CAAC,WAAW,CAAC,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC;aAC3D;YAED,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,UAAU,KAAI,IAAI,EAAE;gBACzC,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC;gBAEvC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBACb,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,OAAO,GAAG,MAAA,OAAO,CAAC,WAAW,0CAAE,WAAW,CAAC;gBAC/C,IAAI,OAAO,IAAI,IAAI,EAAE;oBACjB,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;iBAC7B;qBACI;oBACD,OAAO,CAAC,WAAW,CAAC,WAAW,GAAG,MAAM,CAAC;iBAC5C;gBACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;oBAC1B,MAAM,CAAC,UAAU,EAAE,CAAC;oBACpB,OAAO,CAAC,CAAC;gBACb,CAAC,CAAC,CAAC;aACN;SACJ;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;IAEzB,CAAC;CAEJ"} -------------------------------------------------------------------------------- /dist/intercepters/retry-intercepter.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"retry-intercepter.js","sourceRoot":"","sources":["../../src/intercepters/retry-intercepter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC;;GAEG;AACH,MAAM,OAAO,gBAAgB;IACzB,YAAmB,oBAA4B,CAAC,EAAS,oBAA4B,IAAI;QAAtE,sBAAiB,GAAjB,iBAAiB,CAAY;QAAS,sBAAiB,GAAjB,iBAAiB,CAAe;IACzF,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAkC,EAAE,IAAyB;;QACtE,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,YAAY,KAAI,IAAI,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,UAAU,KAAI,CAAC,EAAE;YACnF,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;SAC9B;QACD,IAAI,UAAU,GAAG,MAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,UAAU,mCAAI,IAAI,CAAC,iBAAiB,CAAC;QAC3E,IAAI,UAAU,GAAG,MAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,UAAU,mCAAI,IAAI,CAAC,iBAAiB,CAAC;QAC3E,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,IAAI,QAAoC,CAAC;QACzC,IAAI;YACA,GAAG;gBACC,IAAI;oBACA,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC/B,OAAO,QAAQ,CAAC;iBACnB;gBACD,OAAO,CAAC,EAAE;oBACN,IAAG,CAAC,YAAY,WAAW,EAAC;wBACxB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;wBAC3B,MAAM,CAAC,CAAC;qBACX;oBACD,IAAI,OAAO,GAAG,UAAU,EAAE;wBACtB,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,IAAI,UAAU,MAAM,CAAC,CAAA;qBAC7D;yBACI;wBACD,OAAO,CAAC,GAAG,CAAC,uBAAuB,OAAO,IAAI,UAAU,IAAI,CAAC,CAAA;qBAChE;oBACD,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACf,IAAG,OAAO,UAAU,KAAK,QAAQ,EAAC;wBAC9B,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;qBAChC;oBACD,IAAG,OAAO,IAAI,UAAU,EAAC;wBACrB,MAAM,CAAC,CAAC;qBACX;iBAEJ;gBACD,OAAO,IAAI,CAAC,CAAC;aAChB,QAAQ,IAAI,EAAC;SACjB;QACD,OAAO,CAAC,EAAE;YACN,MAAM,CAAC,CAAC;SACX;IACL,CAAC;CAEJ"} -------------------------------------------------------------------------------- /demo/demo/src/components/demo1.vue: -------------------------------------------------------------------------------- 1 | 10 | 41 | 42 | 54 | -------------------------------------------------------------------------------- /demo/demo/src/components/demo4.vue: -------------------------------------------------------------------------------- 1 | 8 | 44 | 45 | 57 | -------------------------------------------------------------------------------- /dist/cancel-token.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"cancel-token.js","sourceRoot":"","sources":["../src/cancel-token.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,4FAA4F;AAC5F,+EAA+E;AAE/E,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC;;GAEG;AACH,MAAM,OAAO,WAAW;IAKpB,YAAY,MAA8B;QAkB1C,eAAU,GAAY,KAAK,CAAC;QAqCpB,aAAQ,GAAwC,EAAE,CAAC;QAtDvD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC5B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;SAC5B;aACI,IAAI,MAAM,IAAI,IAAI,EAAE;YACrB,OAAO;SACV;aACI;YACD,IAAI;gBACA,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;aACvC;YACD,OAAO,CAAC,EAAE;gBACN,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,EAAE,CAAC,CAAA;aACtG;SACJ;IAEL,CAAC;IAKD,eAAe;QACX,IAAI,IAAI,CAAC,UAAU,EAAE;YACjB,MAAM,IAAI,WAAW,EAAE,CAAA;SAC1B;IACL,CAAC;IAID,SAAS,CAAC,KAAmB;QACzB,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvC,CAAC;IAID,WAAW,CAAC,MAAc;QACtB,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,CAAC,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QAClB,CAAC,EAAE,MAAM,CAAC,CAAC;QACX,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,UAAU;QACN,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM;QACF,IAAI,IAAI,CAAC,UAAU,IAAI,KAAK,EAAE;YAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACvB,IAAI,CAAC,aAAa,EAAE,CAAC;SACxB;IACL,CAAC;IAIO,aAAa;QACjB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;YAC7B,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YAChC,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAG,IAAI,CAAC,CAAC;SACf;IACL,CAAC;IAED,QAAQ,CAAC,MAAoC;QACzC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,UAAU,EAAE;YACjB,4CAA4C;YAC5C,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,0CAA0C;SACnE;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAGD,QAAQ;QACJ,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ"} -------------------------------------------------------------------------------- /dist/intercepters/auto-domain-intercepter.js: -------------------------------------------------------------------------------- 1 | import { CancelError } from '../errors'; 2 | export class AutoDomainIntercepter { 3 | /** 4 | * 5 | * @param factory return a baseurl, not full url 6 | */ 7 | constructor(factory) { 8 | this.factory = factory; 9 | } 10 | handle(request, next) { 11 | var _a, _b; 12 | if ((_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) { 13 | if (request.pipeOptions.cancelToken.isCanceled) { 14 | return new Promise((resolve, reject) => { 15 | reject(new CancelError()); 16 | }); 17 | } 18 | } 19 | if (((_b = request.pipeOptions) === null || _b === void 0 ? void 0 : _b.preventAutoDomain) != true) { 20 | if (request.url.toLowerCase().indexOf("http://") < 0 && 21 | request.url.toLowerCase().indexOf("https://") < 0) { 22 | //console.log(`auto domain intercepter enter`); 23 | if (request.url[0] != "/") { 24 | request.url = "/" + request.url; 25 | } 26 | let baseUrl = this.factory(request.url); 27 | if (baseUrl.lastIndexOf("/") == (baseUrl.length - 1)) { 28 | baseUrl = baseUrl.substr(0, baseUrl.length - 1); 29 | } 30 | request.url = baseUrl + request.url; 31 | } 32 | //return next(request).then(x=> { x.data = `your json` ; return x;}) 33 | } 34 | return next(request); 35 | } 36 | } 37 | //# sourceMappingURL=auto-domain-intercepter.js.map -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const plugins = [] 2 | 3 | if (process.env.UNI_OPT_TREESHAKINGNG) { 4 | plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js')) 5 | } 6 | 7 | if ( 8 | ( 9 | process.env.UNI_PLATFORM === 'app-plus' && 10 | process.env.UNI_USING_V8 11 | ) || 12 | ( 13 | process.env.UNI_PLATFORM === 'h5' && 14 | process.env.UNI_H5_BROWSER === 'builtin' 15 | ) 16 | ) { 17 | const path = require('path') 18 | 19 | const isWin = /^win/.test(process.platform) 20 | 21 | const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path) 22 | 23 | const input = normalizePath(process.env.UNI_INPUT_DIR) 24 | try { 25 | plugins.push([ 26 | require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'), 27 | { 28 | file (file) { 29 | file = normalizePath(file) 30 | if (file.indexOf(input) === 0) { 31 | return path.relative(input, file) 32 | } 33 | return false 34 | } 35 | } 36 | ]) 37 | } catch (e) {} 38 | } 39 | 40 | process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui'] 41 | process.UNI_LIBRARIES.forEach(libraryName => { 42 | plugins.push([ 43 | 'import', 44 | { 45 | 'libraryName': libraryName, 46 | 'customName': (name) => { 47 | return `${libraryName}/lib/${name}/${name}` 48 | } 49 | } 50 | ]) 51 | }) 52 | module.exports = { 53 | presets: [ 54 | [ 55 | '@vue/app', 56 | { 57 | modules: 'commonjs', 58 | useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry' 59 | } 60 | ] 61 | ], 62 | plugins 63 | } 64 | -------------------------------------------------------------------------------- /demo/demo/babel.config.js: -------------------------------------------------------------------------------- 1 | const plugins = [] 2 | 3 | if (process.env.UNI_OPT_TREESHAKINGNG) { 4 | plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js')) 5 | } 6 | 7 | if ( 8 | ( 9 | process.env.UNI_PLATFORM === 'app-plus' && 10 | process.env.UNI_USING_V8 11 | ) || 12 | ( 13 | process.env.UNI_PLATFORM === 'h5' && 14 | process.env.UNI_H5_BROWSER === 'builtin' 15 | ) 16 | ) { 17 | const path = require('path') 18 | 19 | const isWin = /^win/.test(process.platform) 20 | 21 | const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path) 22 | 23 | const input = normalizePath(process.env.UNI_INPUT_DIR) 24 | try { 25 | plugins.push([ 26 | require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'), 27 | { 28 | file (file) { 29 | file = normalizePath(file) 30 | if (file.indexOf(input) === 0) { 31 | return path.relative(input, file) 32 | } 33 | return false 34 | } 35 | } 36 | ]) 37 | } catch (e) {} 38 | } 39 | 40 | process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui'] 41 | process.UNI_LIBRARIES.forEach(libraryName => { 42 | plugins.push([ 43 | 'import', 44 | { 45 | 'libraryName': libraryName, 46 | 'customName': (name) => { 47 | return `${libraryName}/lib/${name}/${name}` 48 | } 49 | } 50 | ]) 51 | }) 52 | module.exports = { 53 | presets: [ 54 | [ 55 | '@vue/app', 56 | { 57 | modules: 'commonjs', 58 | useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry' 59 | } 60 | ] 61 | ], 62 | plugins 63 | } 64 | -------------------------------------------------------------------------------- /demo/demo/src/components/demo3.vue: -------------------------------------------------------------------------------- 1 | 11 | 44 | 45 | 57 | -------------------------------------------------------------------------------- /src/intercepters/auto-domain-intercepter.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | HttpClientIntercepter, 3 | IntercepterRequestContext, 4 | IntercepterResponseContext, 5 | IntercepterDelegate 6 | } from "../intercepter"; 7 | import { CancelError } from '../errors'; 8 | export class AutoDomainIntercepter implements HttpClientIntercepter { 9 | /** 10 | * 11 | * @param factory return a baseurl, not full url 12 | */ 13 | constructor(public factory: (url: string) => string) { } 14 | 15 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 16 | if(request.pipeOptions?.cancelToken){ 17 | if(request.pipeOptions.cancelToken.isCanceled){ 18 | return new Promise((resolve,reject)=>{ 19 | reject(new CancelError()); 20 | }) 21 | } 22 | } 23 | if (request.pipeOptions?.preventAutoDomain != true) { 24 | 25 | if ( 26 | request.url.toLowerCase().indexOf("http://") < 0 && 27 | request.url.toLowerCase().indexOf("https://") < 0 28 | ) { 29 | //console.log(`auto domain intercepter enter`); 30 | if (request.url[0] != "/") { 31 | request.url = "/" + request.url; 32 | } 33 | let baseUrl = this.factory(request.url); 34 | if (baseUrl.lastIndexOf("/") == (baseUrl.length - 1)) { 35 | baseUrl = baseUrl.substr(0, baseUrl.length - 1); 36 | } 37 | request.url = baseUrl + request.url; 38 | } 39 | 40 | //return next(request).then(x=> { x.data = `your json` ; return x;}) 41 | } 42 | 43 | return next(request); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/intercepters/max-timeout-intercepter.ts: -------------------------------------------------------------------------------- 1 | import { CancelToken } from '../cancel-token'; 2 | import { CancelError } from '../errors'; 3 | import { Task } from '../task/task'; 4 | import type { HttpClientIntercepter, IntercepterDelegate, IntercepterRequestContext, IntercepterResponseContext } from '../intercepter'; 5 | 6 | export class MaxTimeoutIntercepter implements HttpClientIntercepter{ 7 | 8 | constructor(public maxTimeoutSeconds:number = 30){ 9 | 10 | } 11 | 12 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 13 | if(request?.pipeOptions?.cancelToken?.isCanceled){ 14 | return Task.fromError(new CancelError()) 15 | } 16 | 17 | if (request.pipeOptions?.preventTimeout != true) { 18 | if (this.maxTimeoutSeconds != null && this.maxTimeoutSeconds > 0) { 19 | if (request.pipeOptions == null) { 20 | request.pipeOptions = {}; 21 | } 22 | request.pipeOptions.maxTimeout = this.maxTimeoutSeconds; 23 | } 24 | 25 | if (request.pipeOptions?.maxTimeout != null) { 26 | let t = request.pipeOptions.maxTimeout; 27 | 28 | t = t * 1000; 29 | let cancel = new CancelToken(t); 30 | let ocancel = request.pipeOptions?.cancelToken; 31 | if (ocancel != null) { 32 | cancel.linkToken(ocancel); 33 | } 34 | else { 35 | request.pipeOptions.cancelToken = cancel; 36 | } 37 | return next(request).then(x => { 38 | cancel.stopCancel(); 39 | return x; 40 | }); 41 | } 42 | } 43 | return next(request); 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /demo/demo/src/uni.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里是uni-app内置的常用样式变量 3 | * 4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App 6 | * 7 | */ 8 | 9 | /** 10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 11 | * 12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 13 | */ 14 | 15 | /* 颜色变量 */ 16 | 17 | /* 行为相关颜色 */ 18 | $uni-color-primary: #007aff; 19 | $uni-color-success: #4cd964; 20 | $uni-color-warning: #f0ad4e; 21 | $uni-color-error: #dd524d; 22 | 23 | /* 文字基本颜色 */ 24 | $uni-text-color:#333;//基本色 25 | $uni-text-color-inverse:#fff;//反色 26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 27 | $uni-text-color-placeholder: #808080; 28 | $uni-text-color-disable:#c0c0c0; 29 | 30 | /* 背景颜色 */ 31 | $uni-bg-color:#ffffff; 32 | $uni-bg-color-grey:#f8f8f8; 33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色 34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 35 | 36 | /* 边框颜色 */ 37 | $uni-border-color:#c8c7cc; 38 | 39 | /* 尺寸变量 */ 40 | 41 | /* 文字尺寸 */ 42 | $uni-font-size-sm:24rpx; 43 | $uni-font-size-base:28rpx; 44 | $uni-font-size-lg:32rpx; 45 | 46 | /* 图片尺寸 */ 47 | $uni-img-size-sm:40rpx; 48 | $uni-img-size-base:52rpx; 49 | $uni-img-size-lg:80rpx; 50 | 51 | /* Border Radius */ 52 | $uni-border-radius-sm: 4rpx; 53 | $uni-border-radius-base: 6rpx; 54 | $uni-border-radius-lg: 12rpx; 55 | $uni-border-radius-circle: 50%; 56 | 57 | /* 水平间距 */ 58 | $uni-spacing-row-sm: 10px; 59 | $uni-spacing-row-base: 20rpx; 60 | $uni-spacing-row-lg: 30rpx; 61 | 62 | /* 垂直间距 */ 63 | $uni-spacing-col-sm: 8rpx; 64 | $uni-spacing-col-base: 16rpx; 65 | $uni-spacing-col-lg: 24rpx; 66 | 67 | /* 透明度 */ 68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 69 | 70 | /* 文章场景相关 */ 71 | $uni-color-title: #2C405A; // 文章标题颜色 72 | $uni-font-size-title:40rpx; 73 | $uni-color-subtitle: #555555; // 二级标题颜色 74 | $uni-font-size-subtitle:36rpx; 75 | $uni-color-paragraph: #3F536E; // 文章段落颜色 76 | $uni-font-size-paragraph:30rpx; -------------------------------------------------------------------------------- /dist/intercepters/jwt-token-intercepter.js: -------------------------------------------------------------------------------- 1 | import { CancelError } from '../errors'; 2 | const AuthKey = "Authorization"; 3 | export class JwtTokenIntercepter { 4 | constructor(tokenFactory) { 5 | this.tokenFactory = tokenFactory; 6 | } 7 | handle(request, next) { 8 | var _a, _b, _c; 9 | if ((_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) { 10 | if (request.pipeOptions.cancelToken.isCanceled) { 11 | return new Promise((resolve, reject) => { 12 | reject(new CancelError()); 13 | }); 14 | } 15 | } 16 | if (((_b = request.pipeOptions) === null || _b === void 0 ? void 0 : _b.preventJwtToken) != true) { 17 | //console.log(`token intercepter enter`) 18 | request.header = (_c = request.header) !== null && _c !== void 0 ? _c : {}; 19 | // this will disallow this intercepter when Authentication set to null 20 | if (request.header[AuthKey] === null) { 21 | delete request.header[AuthKey]; 22 | } 23 | else if (request.header[AuthKey] === undefined) { 24 | const token = this.tokenFactory(request.url); 25 | //console.log(token); 26 | if (token instanceof Promise) { 27 | return token.then(t => { 28 | if (t != null && t != '') { 29 | request.header[AuthKey] = `Bearer ${t}`; 30 | } 31 | }).then(() => next(request)); 32 | } 33 | else if (token != null) { 34 | request.header[AuthKey] = `Bearer ${token}`; 35 | } 36 | } 37 | } 38 | //return next(request).then(x=> { x.data = `your json` ; return x;}) 39 | return next(request); 40 | } 41 | } 42 | //# sourceMappingURL=jwt-token-intercepter.js.map -------------------------------------------------------------------------------- /dist/intercepters/max-timeout-intercepter.js: -------------------------------------------------------------------------------- 1 | import { CancelToken } from '../cancel-token'; 2 | import { CancelError } from '../errors'; 3 | import { Task } from '../task/task'; 4 | export class MaxTimeoutIntercepter { 5 | constructor(maxTimeoutSeconds = 30) { 6 | this.maxTimeoutSeconds = maxTimeoutSeconds; 7 | } 8 | handle(request, next) { 9 | var _a, _b, _c, _d, _e; 10 | if ((_b = (_a = request === null || request === void 0 ? void 0 : request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 11 | return Task.fromError(new CancelError()); 12 | } 13 | if (((_c = request.pipeOptions) === null || _c === void 0 ? void 0 : _c.preventTimeout) != true) { 14 | if (this.maxTimeoutSeconds != null && this.maxTimeoutSeconds > 0) { 15 | if (request.pipeOptions == null) { 16 | request.pipeOptions = {}; 17 | } 18 | request.pipeOptions.maxTimeout = this.maxTimeoutSeconds; 19 | } 20 | if (((_d = request.pipeOptions) === null || _d === void 0 ? void 0 : _d.maxTimeout) != null) { 21 | let t = request.pipeOptions.maxTimeout; 22 | t = t * 1000; 23 | let cancel = new CancelToken(t); 24 | let ocancel = (_e = request.pipeOptions) === null || _e === void 0 ? void 0 : _e.cancelToken; 25 | if (ocancel != null) { 26 | cancel.linkToken(ocancel); 27 | } 28 | else { 29 | request.pipeOptions.cancelToken = cancel; 30 | } 31 | return next(request).then(x => { 32 | cancel.stopCancel(); 33 | return x; 34 | }); 35 | } 36 | } 37 | return next(request); 38 | } 39 | } 40 | //# sourceMappingURL=max-timeout-intercepter.js.map -------------------------------------------------------------------------------- /dist/intercepters/timeout-interceper.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"timeout-interceper.js","sourceRoot":"","sources":["../../src/intercepters/timeout-interceper.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,OAAO,kBAAkB;IAI3B;;;OAGG;IACH,YAAmB,kBAA2B;QAA3B,uBAAkB,GAAlB,kBAAkB,CAAS;QAN7B,SAAI,GAAG,+BAA+B,CAAC;IAQxD,CAAC;IAED,MAAM,CAAC,OAAkC,EAAE,IAAyB;;QAChE,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,WAAW,KAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAG,IAAI,CAAC,IAAI,CAAC,KAAI,IAAI,EAAE;YAC9E,kBAAkB;YAClB,IAAI,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,UAAU,EAAE;gBAC5C,OAAO,IAAI,OAAO,CAA6B,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBAC/D,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,CAAC;gBAC9B,CAAC,CAAC,CAAA;aACL;SACJ;QACD,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,cAAc,KAAI,IAAI,EAAE;YAC7C,IAAI,IAAI,CAAC,kBAAkB,IAAI,IAAI,IAAI,IAAI,CAAC,kBAAkB,GAAG,CAAC,EAAE;gBAChE,IAAI,OAAO,CAAC,WAAW,IAAI,IAAI,EAAE;oBAC7B,OAAO,CAAC,WAAW,GAAG,EAAE,CAAC;oBACzB,OAAO,CAAC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC;iBACzD;aAEJ;YAED,IAAI,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,OAAO,KAAI,IAAI,EAAE;gBACtC,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;gBAEpC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;gBACb,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,OAAO,GAAG,CAAA,MAAA,OAAO,CAAC,WAAW,0CAAG,IAAI,CAAC,IAAI,CAAC,KAAI,IAAI,CAAC,CAAC,CAAC,MAAA,OAAO,CAAC,WAAW,0CAAE,4BAA4B,CAAC,CAAC,CAAC,MAAA,OAAO,CAAC,WAAW,0CAAE,WAAW,CAAC;gBAC9I,IAAI,OAAO,IAAI,IAAI,EAAE;oBACjB,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;oBAC1B,OAAO,CAAC,WAAW,CAAC,4BAA4B,GAAG,OAAO,CAAC;iBAC9D;gBACD,OAAO,CAAC,WAAW,CAAC,WAAW,GAAG,MAAM,CAAC;gBACzC,+BAA+B;gBAC/B,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;gBACtC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;oBAC1B,MAAM,CAAC,UAAU,EAAE,CAAC;oBACpB,IAAG,OAAO,CAAC,WAAW,IAAG,IAAI,EAAC;wBAC1B,8CAA8C;wBAC9C,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;wBACvC,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;qBACzC;oBAED,OAAO,CAAC,CAAC;gBACb,CAAC,CAAC,CAAC;aACN;SACJ;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC;IAGzB,CAAC;CAEJ"} -------------------------------------------------------------------------------- /dist/task/task.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/task/task.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE1C,MAAM,OAAO,IAAI;IACb;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,EAAU,EAAE,WAA0B;QAC/C,IAAI,IAAI,GAAG,IAAI,UAAU,EAAQ,CAAC;QAClC,UAAU,CAAC,GAAG,EAAE;YACZ,IAAI,CAAC,SAAS,EAAE,CAAC;QACrB,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,IAAI,WAAW,EAAE;YACb,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAA;SACxE;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,KAAqB;QAChC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,EAAE;YACjC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;SACjD;QACD,IAAI,IAAI,GAAG,IAAI,UAAU,EAAE,CAAC;QAC5B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAEhF,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,KAAqB;QAChC,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,EAAE;YACjC,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;SACjD;QACD,IAAI,IAAI,GAAG,IAAI,UAAU,EAAQ,CAAC;QAClC,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QACzB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,SAAS,WAAW,CAAC,KAAc;YAC/B,cAAc,EAAE,CAAC;YACjB,IAAI,cAAc,IAAI,KAAK,EAAE;gBACzB,IAAI,QAAQ,EAAE;oBACV,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAA;iBACrD;qBACI;oBACD,IAAI,CAAC,SAAS,EAAE,CAAC;iBACpB;aACJ;QACL,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YACd,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;iBAC3B,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,SAAS,CAAU,IAAO;QAC7B,IAAI,IAAI,GAAG,IAAI,UAAU,EAAK,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,SAAS,CAAU,KAAkB;QACxC,IAAI,IAAI,GAAG,IAAI,UAAU,EAAK,CAAC;QAC/B,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA,EAAE,CAAA,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;QACtC,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;CACJ"} -------------------------------------------------------------------------------- /dist/errors.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAGtC,YAAmB,UAAkB,EAAS,OAA2B;QACrE,KAAK,CAAC,eAAe,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;QAD/B,eAAU,GAAV,UAAU,CAAQ;QAAS,YAAO,GAAP,OAAO,CAAoB;QAErE,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC;IAE1C,CAAC;IA0BD,MAAM,CAAC,UAAU,CAAC,UAAkB;QAChC,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,GAAG,IAAI,IAAI,EAAE;YACb,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAC;SAChC;aACI;YACD,OAAO,GAAG,UAAU,IAAI,GAAG,EAAE,CAAC;SACjC;IACL,CAAC;IAED,iBAAiB;QACb,IAAI,GAAG,GAAG,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtD,IAAG,GAAG,IAAI,IAAI,EAAC;YACX,IAAG,GAAG,CAAC,OAAO,IAAI,IAAI,EAAC;gBACnB,OAAO,GAAG,CAAC,OAAO,CAAC;aACtB;YACD,OAAO,GAAG,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,KAAK,EAAE,CAAA;SAC3C;QACD,OAAO,GAAG,IAAI,CAAC,UAAU,OAAO,CAAC;IACrC,CAAC;;AA3CM,0BAAU,GAEb;IACI,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG;IACrB,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE;IAC1C,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG;IAC3B,GAAG,EAAE,EAAE,KAAK,EAAE,+BAA+B,EAAE;IAC/C,GAAG,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE;IAC5B,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE;IACnC,GAAG,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE;IAClC,GAAG,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE;IAC9B,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE;IACpC,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE;IAC7B,GAAG,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE;IACrD,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG;IAC9C,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG;IAC9C,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE;IACpC,GAAG,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,QAAQ,GAAG;IACrD,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,aAAa,GAAG;IAChE,GAAG,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,GAAG;IACvD,GAAG,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAE,cAAc,GAAG;IAC/D,GAAG,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE;CAC/C,CAAA;AAyBT,MAAM,OAAO,WAAY,SAAQ,KAAK;IAElC,YAAY,UAAkB,kBAAkB;QAC5C,KAAK,CAAC,OAAO,CAAC,CAAC;QAInB,kBAAa,GAAG,IAAI,CAAC;QAHjB,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,qCAAqC;IAChF,CAAC;CAGJ"} -------------------------------------------------------------------------------- /src/intercepters/jwt-token-intercepter.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterResponseContext, IntercepterDelegate } from "../intercepter"; 2 | import { CancelError } from '../errors'; 3 | const AuthKey = "Authorization"; 4 | export class JwtTokenIntercepter implements HttpClientIntercepter { 5 | 6 | constructor(private tokenFactory: (url: string) => string | null | Promise) { 7 | 8 | } 9 | 10 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 11 | if(request.pipeOptions?.cancelToken){ 12 | if(request.pipeOptions.cancelToken.isCanceled){ 13 | return new Promise((resolve,reject)=>{ 14 | reject(new CancelError()); 15 | }) 16 | } 17 | } 18 | if (request.pipeOptions?.preventJwtToken != true) { 19 | //console.log(`token intercepter enter`) 20 | request.header = request.header ?? {}; 21 | // this will disallow this intercepter when Authentication set to null 22 | if (request.header[AuthKey] === null) { 23 | delete request.header[AuthKey]; 24 | } 25 | else if (request.header[AuthKey] === undefined) { 26 | const token = this.tokenFactory(request.url); 27 | //console.log(token); 28 | if( token instanceof Promise){ 29 | return token.then(t=>{ 30 | if(t != null && t != ''){ 31 | request.header[AuthKey] = `Bearer ${t}` 32 | } 33 | }).then(()=> next(request)); 34 | } 35 | else if (token != null) { 36 | request.header[AuthKey] = `Bearer ${token}` 37 | } 38 | 39 | } 40 | } 41 | 42 | 43 | //return next(request).then(x=> { x.data = `your json` ; return x;}) 44 | return next(request); 45 | 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/intercepters/retry-intercepter.ts: -------------------------------------------------------------------------------- 1 | import { Task } from '../task/task'; 2 | import type { HttpClientIntercepter, IntercepterDelegate, IntercepterRequestContext, IntercepterResponseContext } from '../intercepter'; 3 | import { CancelError } from '../errors'; 4 | 5 | /** 6 | * 重试拦截器 7 | */ 8 | export class RetryIntercepter implements HttpClientIntercepter { 9 | constructor(public defaultRetrycount: number = 1, public defaultRetryDelay: number = 1000) { 10 | } 11 | 12 | async handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 13 | if (request.pipeOptions?.preventRetry == true || request.pipeOptions?.retryCount == 0) { 14 | return await next(request); 15 | } 16 | let retryCount = request.pipeOptions?.retryCount ?? this.defaultRetrycount; 17 | let retryDelay = request.pipeOptions?.retryDelay ?? this.defaultRetryDelay; 18 | let current = 0; 19 | let response: IntercepterResponseContext; 20 | try { 21 | do { 22 | try { 23 | response = await next(request); 24 | return response; 25 | } 26 | catch (e) { 27 | if(e instanceof CancelError){ 28 | console.log(`retry cancel`) 29 | throw e; 30 | } 31 | if (current < retryCount) { 32 | console.log(`error:retrying(${current}/${retryCount})...`) 33 | } 34 | else { 35 | console.log(`error:done retrying(${current}/${retryCount}).`) 36 | } 37 | console.log(e); 38 | if(typeof retryDelay === "number"){ 39 | await Task.delay(retryDelay); 40 | } 41 | if(current >= retryCount){ 42 | throw e; 43 | } 44 | 45 | } 46 | current += 1; 47 | } while (true) 48 | } 49 | catch (e) { 50 | throw e; 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /dist/errors.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 状态码错误 3 | */ 4 | export class StatusCodeError extends Error { 5 | constructor(statusCode, respose) { 6 | super(StatusCodeError.getMessage(statusCode)); 7 | this.statusCode = statusCode; 8 | this.respose = respose; 9 | this.__proto__ = new.target.prototype; 10 | } 11 | static getMessage(statusCode) { 12 | let msg = this.messageMap[200]; 13 | if (msg == null) { 14 | return statusCode.toString(); 15 | } 16 | else { 17 | return `${statusCode} ${msg}`; 18 | } 19 | } 20 | getDisplayMessage() { 21 | let msg = StatusCodeError.messageMap[this.statusCode]; 22 | if (msg != null) { 23 | if (msg.display != null) { 24 | return msg.display; 25 | } 26 | return `${this.statusCode} ${msg.label}`; 27 | } 28 | return `${this.statusCode} 未知错误`; 29 | } 30 | } 31 | StatusCodeError.messageMap = { 32 | 200: { label: "OK", }, 33 | 201: { label: "Created", display: "创建成功" }, 34 | 202: { label: "Accepted", }, 35 | 203: { label: "Non-Authoritative Information" }, 36 | 204: { label: "No Content" }, 37 | 301: { label: "Moved Permanently" }, 38 | 302: { label: "Move Temporarily" }, 39 | 304: { label: "Not Modified" }, 40 | 307: { label: "Temporary Redirect" }, 41 | 400: { label: "Bad Request" }, 42 | 401: { label: "Unauthorized", display: "您未登录或登录已过期" }, 43 | 403: { label: "Forbidden", display: "您没有权限", }, 44 | 404: { label: "Not Found", display: "资源不见了", }, 45 | 405: { label: "Method Not Allowed" }, 46 | 408: { label: "Request Timeout", display: "发送请求超时", }, 47 | 500: { label: "Internal Server Error", display: "服务出错了,请稍后再试", }, 48 | 502: { label: "Bad Gateway", display: "服务暂不可用,请稍后再试", }, 49 | 503: { label: "Service Unavailable", display: "服务暂不可用,请稍后再试", }, 50 | 505: { label: "HTTP Version Not Supported" }, 51 | }; 52 | export class CancelError extends Error { 53 | constructor(message = "Promise Canceled") { 54 | super(message); 55 | this.isCancelError = true; 56 | this.__proto__ = new.target.prototype; // fix an error when downlevel to es5 57 | } 58 | } 59 | //# sourceMappingURL=errors.js.map -------------------------------------------------------------------------------- /dist/task/task.js: -------------------------------------------------------------------------------- 1 | import { TaskSource } from './task-source'; 2 | export class Task { 3 | /** 4 | * 延时一段时间 5 | * @param ms 延时的时间 单位毫秒 6 | * @param cancelToken 取消令牌 7 | */ 8 | static delay(ms, cancelToken) { 9 | let task = new TaskSource(); 10 | setTimeout(() => { 11 | task.setResult(); 12 | }, ms); 13 | if (cancelToken) { 14 | cancelToken.register(x => task.setError(new Error(`delay Canceled`))); 15 | } 16 | return task.task; 17 | } 18 | /** 19 | * 等待其中一个@see Promise 完成 20 | * @param tasks 一个promise 数组 21 | */ 22 | static whenAny(tasks) { 23 | if (tasks instanceof Array == false) { 24 | throw new Error(`parameter must be an array`); 25 | } 26 | let task = new TaskSource(); 27 | tasks.forEach(x => x.then(r => task.setResult(x)).catch(e => task.setResult(x))); 28 | return task.task; 29 | } 30 | /** 31 | * 等待所有的promise完成 32 | * @param tasks 一个promise 数组 33 | */ 34 | static whenAll(tasks) { 35 | if (tasks instanceof Array == false) { 36 | throw new Error(`parameter must be an array`); 37 | } 38 | let task = new TaskSource(); 39 | let count = tasks.length; 40 | let hasError = false; 41 | let completedCount = 0; 42 | function addComplate(error) { 43 | completedCount++; 44 | if (completedCount >= count) { 45 | if (hasError) { 46 | task.setError(new Error(`some of the tasks fail`)); 47 | } 48 | else { 49 | task.setResult(); 50 | } 51 | } 52 | } 53 | tasks.forEach(x => { 54 | x.then(() => addComplate(false)) 55 | .catch(e => addComplate(true)); 56 | }); 57 | return task.task; 58 | } 59 | static fromReult(data) { 60 | let task = new TaskSource(); 61 | task.setResult(data); 62 | return task.task; 63 | } 64 | static fromError(error) { 65 | let task = new TaskSource(); 66 | task.startAction(x => x.setError(error)); 67 | return task.task; 68 | } 69 | } 70 | //# sourceMappingURL=task.js.map -------------------------------------------------------------------------------- /dist/cancel-token.js: -------------------------------------------------------------------------------- 1 | // 我尝试复刻 C# 里面的 CancellationToken 和 CancellationTokenSource, 发现 C# 之所以分离这两个,有一部分是设计原则的问题, 2 | // 还有一个就是 CancellationToken 是一个 struct , 它永远不会变成null, 但这在 ts/js 中是无法实现的,所以混合这两者的功能,以便更方面的调用, 3 | // 但是从原则来讲,使用token 的一方, 不应该调用任何跟 Cancel相关的主动方法, 请看 ICancelToken 和 ICancelSource 4 | import { CancelError } from './errors'; 5 | /** 6 | * a CancelToken that support safe cancellation 7 | */ 8 | export class CancelToken { 9 | constructor(option) { 10 | this.isCanceled = false; 11 | this._actions = []; 12 | if (typeof option === "number") { 13 | this.cancelAfter(option); 14 | } 15 | else if (option == null) { 16 | return; 17 | } 18 | else { 19 | try { 20 | option.register(x => this.cancel()); 21 | } 22 | catch (e) { 23 | throw new Error(`argument must be a instace of interface ICancelToken or class CancelToken : ${e}`); 24 | } 25 | } 26 | } 27 | throwIfCanceled() { 28 | if (this.isCanceled) { 29 | throw new CancelError(); 30 | } 31 | } 32 | linkToken(token) { 33 | token.register(x => this.cancel()); 34 | } 35 | cancelAfter(timems) { 36 | clearTimeout(this._t); 37 | this._t = setTimeout(() => { 38 | this.cancel(); 39 | }, timems); 40 | return this; 41 | } 42 | stopCancel() { 43 | clearTimeout(this._t); 44 | return this; 45 | } 46 | cancel() { 47 | if (this.isCanceled == false) { 48 | this.isCanceled = true; 49 | this.triggerAction(); 50 | } 51 | } 52 | triggerAction() { 53 | while (this._actions.length > 0) { 54 | let act = this._actions.shift(); 55 | act === null || act === void 0 ? void 0 : act(this); 56 | } 57 | } 58 | register(action) { 59 | this._actions.push(action); 60 | if (this.isCanceled) { 61 | // already canceled , so only trigger cancel 62 | this.triggerAction(); // after trigger the action will be remove 63 | } 64 | return this; 65 | } 66 | getToken() { 67 | return this; 68 | } 69 | } 70 | //# sourceMappingURL=cancel-token.js.map -------------------------------------------------------------------------------- /dist/intercepters/retry-intercepter.js: -------------------------------------------------------------------------------- 1 | import { Task } from '../task/task'; 2 | import { CancelError } from '../errors'; 3 | /** 4 | * 重试拦截器 5 | */ 6 | export class RetryIntercepter { 7 | constructor(defaultRetrycount = 1, defaultRetryDelay = 1000) { 8 | this.defaultRetrycount = defaultRetrycount; 9 | this.defaultRetryDelay = defaultRetryDelay; 10 | } 11 | async handle(request, next) { 12 | var _a, _b, _c, _d, _e, _f; 13 | if (((_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.preventRetry) == true || ((_b = request.pipeOptions) === null || _b === void 0 ? void 0 : _b.retryCount) == 0) { 14 | return await next(request); 15 | } 16 | let retryCount = (_d = (_c = request.pipeOptions) === null || _c === void 0 ? void 0 : _c.retryCount) !== null && _d !== void 0 ? _d : this.defaultRetrycount; 17 | let retryDelay = (_f = (_e = request.pipeOptions) === null || _e === void 0 ? void 0 : _e.retryDelay) !== null && _f !== void 0 ? _f : this.defaultRetryDelay; 18 | let current = 0; 19 | let response; 20 | try { 21 | do { 22 | try { 23 | response = await next(request); 24 | return response; 25 | } 26 | catch (e) { 27 | if (e instanceof CancelError) { 28 | console.log(`retry cancel`); 29 | throw e; 30 | } 31 | if (current < retryCount) { 32 | console.log(`error:retrying(${current}/${retryCount})...`); 33 | } 34 | else { 35 | console.log(`error:done retrying(${current}/${retryCount}).`); 36 | } 37 | console.log(e); 38 | if (typeof retryDelay === "number") { 39 | await Task.delay(retryDelay); 40 | } 41 | if (current >= retryCount) { 42 | throw e; 43 | } 44 | } 45 | current += 1; 46 | } while (true); 47 | } 48 | catch (e) { 49 | throw e; 50 | } 51 | } 52 | } 53 | //# sourceMappingURL=retry-intercepter.js.map -------------------------------------------------------------------------------- /dist/token-storages/token-storage.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"token-storage.js","sourceRoot":"","sources":["../../src/token-storages/token-storage.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /src/task/task.ts: -------------------------------------------------------------------------------- 1 | import type { ICancelToken } from '../cancel-token' 2 | import { TaskSource } from './task-source' 3 | 4 | export class Task { 5 | /** 6 | * 延时一段时间 7 | * @param ms 延时的时间 单位毫秒 8 | * @param cancelToken 取消令牌 9 | */ 10 | static delay(ms: number, cancelToken?: ICancelToken) { 11 | let task = new TaskSource(); 12 | setTimeout(() => { 13 | task.setResult(); 14 | }, ms); 15 | if (cancelToken) { 16 | cancelToken.register(x => task.setError(new Error(`delay Canceled`))) 17 | } 18 | return task.task; 19 | } 20 | 21 | /** 22 | * 等待其中一个@see Promise 完成 23 | * @param tasks 一个promise 数组 24 | */ 25 | static whenAny(tasks: Promise[]): Promise> { 26 | if (tasks instanceof Array == false) { 27 | throw new Error(`parameter must be an array`); 28 | } 29 | let task = new TaskSource(); 30 | tasks.forEach(x => x.then(r => task.setResult(x)).catch(e => task.setResult(x))) 31 | 32 | return task.task; 33 | } 34 | 35 | /** 36 | * 等待所有的promise完成 37 | * @param tasks 一个promise 数组 38 | */ 39 | static whenAll(tasks: Promise[]): Promise { 40 | if (tasks instanceof Array == false) { 41 | throw new Error(`parameter must be an array`); 42 | } 43 | let task = new TaskSource(); 44 | let count = tasks.length; 45 | let hasError = false; 46 | let completedCount = 0; 47 | function addComplate(error: boolean) { 48 | completedCount++; 49 | if (completedCount >= count) { 50 | if (hasError) { 51 | task.setError(new Error(`some of the tasks fail`)) 52 | } 53 | else { 54 | task.setResult(); 55 | } 56 | } 57 | } 58 | tasks.forEach(x => { 59 | x.then(() => addComplate(false)) 60 | .catch(e => addComplate(true)) 61 | }) 62 | return task.task; 63 | } 64 | 65 | static fromReult(data: T): Promise { 66 | let task = new TaskSource(); 67 | task.setResult(data); 68 | return task.task; 69 | } 70 | 71 | static fromError(error: Error | any):Promise{ 72 | let task = new TaskSource(); 73 | task.startAction(x=>x.setError(error)) 74 | return task.task; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | import type { ResponseData } from './options'; 2 | 3 | 4 | /** 5 | * 状态码错误 6 | */ 7 | export class StatusCodeError extends Error { 8 | private __proto__: Error; 9 | 10 | constructor(public statusCode: number, public respose?: ResponseData) { 11 | super(StatusCodeError.getMessage(statusCode)); 12 | this.__proto__ = new.target.prototype; 13 | 14 | } 15 | 16 | static messageMap: { 17 | [key: number]: { label: string, display?: string } 18 | } = { 19 | 200: { label: "OK", }, 20 | 201: { label: "Created", display: "创建成功" }, 21 | 202: { label: "Accepted", }, 22 | 203: { label: "Non-Authoritative Information" }, 23 | 204: { label: "No Content" }, 24 | 301: { label: "Moved Permanently" }, 25 | 302: { label: "Move Temporarily" }, 26 | 304: { label: "Not Modified" }, 27 | 307: { label: "Temporary Redirect" }, 28 | 400: { label: "Bad Request" }, 29 | 401: { label: "Unauthorized", display: "您未登录或登录已过期" }, 30 | 403: { label: "Forbidden", display: "您没有权限", }, 31 | 404: { label: "Not Found", display: "资源不见了", }, 32 | 405: { label: "Method Not Allowed" }, 33 | 408: { label: "Request Timeout", display: "发送请求超时", }, 34 | 500: { label: "Internal Server Error", display: "服务出错了,请稍后再试", }, 35 | 502: { label: "Bad Gateway", display: "服务暂不可用,请稍后再试", }, 36 | 503: { label: "Service Unavailable", display: "服务暂不可用,请稍后再试", }, 37 | 505: { label: "HTTP Version Not Supported" }, 38 | } 39 | 40 | static getMessage(statusCode: number): string { 41 | let msg = this.messageMap[200]; 42 | if (msg == null) { 43 | return statusCode.toString(); 44 | } 45 | else { 46 | return `${statusCode} ${msg}`; 47 | } 48 | } 49 | 50 | getDisplayMessage() { 51 | let msg = StatusCodeError.messageMap[this.statusCode]; 52 | if(msg != null){ 53 | if(msg.display != null){ 54 | return msg.display; 55 | } 56 | return `${this.statusCode} ${msg.label}` 57 | } 58 | return `${this.statusCode} 未知错误`; 59 | } 60 | } 61 | 62 | 63 | export class CancelError extends Error { 64 | private __proto__: Error; // object internal field 65 | constructor(message: string = "Promise Canceled") { 66 | super(message); 67 | this.__proto__ = new.target.prototype; // fix an error when downlevel to es5 68 | } 69 | 70 | isCancelError = true; 71 | } 72 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /src/intercepters/timeout-interceper.ts: -------------------------------------------------------------------------------- 1 | import type { HttpClientIntercepter, IntercepterRequestContext, IntercepterDelegate, IntercepterResponseContext } from '../intercepter'; 2 | import { CancelToken } from '../cancel-token'; 3 | import { CancelError } from '../errors'; 4 | 5 | export class TimeoutIntercepter implements HttpClientIntercepter { 6 | 7 | private readonly _key = "__timeoutintercepter_attached"; 8 | 9 | /** 10 | * 支持超时的拦截器 11 | * @param cancelAfterSeconds 全局超时秒数 12 | */ 13 | constructor(public cancelAfterSeconds?: number) { 14 | 15 | } 16 | 17 | handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 18 | if (request.pipeOptions?.cancelToken && request.pipeOptions?.[this._key] != true) { 19 | // 如果已经取消,那就直接返回错误 20 | if (request.pipeOptions.cancelToken.isCanceled) { 21 | return new Promise((resolve, reject) => { 22 | reject(new CancelError()); 23 | }) 24 | } 25 | } 26 | if (request.pipeOptions?.preventTimeout != true) { 27 | if (this.cancelAfterSeconds != null && this.cancelAfterSeconds > 0) { 28 | if (request.pipeOptions == null) { 29 | request.pipeOptions = {}; 30 | request.pipeOptions.timeout = this.cancelAfterSeconds; 31 | } 32 | 33 | } 34 | 35 | if (request.pipeOptions?.timeout != null) { 36 | let t = request.pipeOptions.timeout; 37 | 38 | t = t * 1000; 39 | let cancel = new CancelToken(t); 40 | let ocancel = request.pipeOptions?.[this._key] == true ? request.pipeOptions?.__timeoutintercepter_ocancel : request.pipeOptions?.cancelToken; 41 | if (ocancel != null) { 42 | cancel.linkToken(ocancel); 43 | request.pipeOptions.__timeoutintercepter_ocancel = ocancel; 44 | } 45 | request.pipeOptions.cancelToken = cancel; 46 | // 通过注入这个属性,来通知自己下次的 token 是自己的 47 | request.pipeOptions[this._key] = true; 48 | return next(request).then(x => { 49 | cancel.stopCancel(); 50 | if(request.pipeOptions !=null){ 51 | // 如果允许正常则删除这个, 如果不正常就不删除了,下次 retry的时候就可以重置时间了 52 | request.pipeOptions[this._key] = false; 53 | delete request.pipeOptions[this._key]; 54 | } 55 | 56 | return x; 57 | }); 58 | } 59 | } 60 | return next(request); 61 | 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /dist/intercepters/timeout-interceper.js: -------------------------------------------------------------------------------- 1 | import { CancelToken } from '../cancel-token'; 2 | import { CancelError } from '../errors'; 3 | export class TimeoutIntercepter { 4 | /** 5 | * 支持超时的拦截器 6 | * @param cancelAfterSeconds 全局超时秒数 7 | */ 8 | constructor(cancelAfterSeconds) { 9 | this.cancelAfterSeconds = cancelAfterSeconds; 10 | this._key = "__timeoutintercepter_attached"; 11 | } 12 | handle(request, next) { 13 | var _a, _b, _c, _d, _e, _f, _g; 14 | if (((_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) && ((_b = request.pipeOptions) === null || _b === void 0 ? void 0 : _b[this._key]) != true) { 15 | // 如果已经取消,那就直接返回错误 16 | if (request.pipeOptions.cancelToken.isCanceled) { 17 | return new Promise((resolve, reject) => { 18 | reject(new CancelError()); 19 | }); 20 | } 21 | } 22 | if (((_c = request.pipeOptions) === null || _c === void 0 ? void 0 : _c.preventTimeout) != true) { 23 | if (this.cancelAfterSeconds != null && this.cancelAfterSeconds > 0) { 24 | if (request.pipeOptions == null) { 25 | request.pipeOptions = {}; 26 | request.pipeOptions.timeout = this.cancelAfterSeconds; 27 | } 28 | } 29 | if (((_d = request.pipeOptions) === null || _d === void 0 ? void 0 : _d.timeout) != null) { 30 | let t = request.pipeOptions.timeout; 31 | t = t * 1000; 32 | let cancel = new CancelToken(t); 33 | let ocancel = ((_e = request.pipeOptions) === null || _e === void 0 ? void 0 : _e[this._key]) == true ? (_f = request.pipeOptions) === null || _f === void 0 ? void 0 : _f.__timeoutintercepter_ocancel : (_g = request.pipeOptions) === null || _g === void 0 ? void 0 : _g.cancelToken; 34 | if (ocancel != null) { 35 | cancel.linkToken(ocancel); 36 | request.pipeOptions.__timeoutintercepter_ocancel = ocancel; 37 | } 38 | request.pipeOptions.cancelToken = cancel; 39 | // 通过注入这个属性,来通知自己下次的 token 是自己的 40 | request.pipeOptions[this._key] = true; 41 | return next(request).then(x => { 42 | cancel.stopCancel(); 43 | if (request.pipeOptions != null) { 44 | // 如果允许正常则删除这个, 如果不正常就不删除了,下次 retry的时候就可以重置时间了 45 | request.pipeOptions[this._key] = false; 46 | delete request.pipeOptions[this._key]; 47 | } 48 | return x; 49 | }); 50 | } 51 | } 52 | return next(request); 53 | } 54 | } 55 | //# sourceMappingURL=timeout-interceper.js.map -------------------------------------------------------------------------------- /dist/token-storages/token-storage.js: -------------------------------------------------------------------------------- 1 | export class TokenStorage { 2 | constructor(tokenType) { 3 | this.tokenType = tokenType; 4 | this.expireOffsetMs = -5000; 5 | this.cChar = "#"; 6 | this.akey = "Authentication"; 7 | } 8 | getKey(domain) { 9 | return `${this.akey}${this.cChar}${this.tokenType}${this.cChar}${domain}`; 10 | } 11 | isTokenExpired(domain) { 12 | if (domain == null || domain == "") { 13 | throw new Error("domain can not be null or empty, but you can use '*' "); 14 | } 15 | let token = this.getToken(domain); 16 | return token == null; 17 | } 18 | getToken(domain, includeExpired) { 19 | if (domain == null) { 20 | throw new Error("domain can not be null or empty, but you can use '*'"); 21 | } 22 | const key = this.getKey(domain); 23 | var info = uni.getStorageSync(key); 24 | if (info == null) { 25 | return null; 26 | } 27 | if (includeExpired !== true) { 28 | const epTime = info.expireAt + this.expireOffsetMs; 29 | const epDate = new Date(epTime); 30 | if (new Date() > epDate) { 31 | return null; 32 | } 33 | } 34 | return info.token; 35 | } 36 | /** 37 | * async 允许你挂载 onTokenExpired 钩子函数 38 | */ 39 | getTokenAsync(domain) { 40 | let t = this.getToken(domain); 41 | if (t == null) { 42 | if (this.onTokenExpired != null) { 43 | return this.onTokenExpired(this, domain) 44 | .then(() => this.getToken(domain)); 45 | } 46 | } 47 | return new Promise((resove, reject) => { 48 | resove(this.getToken(domain)); 49 | }); 50 | } 51 | /** 52 | * 设置token 53 | * @param domain 域名, 你可以设置 '*' 但不能是null 54 | * @param expireIn 秒 55 | */ 56 | setToken(domain, token, expireIn) { 57 | if (domain == null) { 58 | throw new Error("domain can not be null or empty, but you can use '*'"); 59 | } 60 | const key = this.getKey(domain); 61 | const cTime = new Date().getTime(); 62 | const eTime = cTime + expireIn * 1000; 63 | const info = { 64 | storageAt: cTime, 65 | expireAt: eTime, 66 | token: token, 67 | }; 68 | uni.setStorageSync(key, info); 69 | } 70 | clearToken(domain) { 71 | if (domain == null) { 72 | throw new Error("domain can not be null or empty, but you can use '*'"); 73 | } 74 | const key = this.getKey(domain); 75 | uni.removeStorageSync(key); 76 | } 77 | } 78 | export const tokenStorage = new TokenStorage("access_token"); 79 | export const freshTokenStorage = new TokenStorage("fresh_token"); 80 | //# sourceMappingURL=token-storage.js.map -------------------------------------------------------------------------------- /dist/options.d.ts: -------------------------------------------------------------------------------- 1 | import type { ICancelToken } from './cancel-token'; 2 | import type { IHttpClientHandler } from './httpclien-handler'; 3 | export interface PipeOptions { 4 | cancelToken?: ICancelToken; 5 | /** 秒数, 必须添加 @see TimeoutIntercepter 才管用 */ 6 | timeout?: number; 7 | /** 秒数,必须添加 @see MaxTimeoutIntercepter 才管用 */ 8 | maxTimeout?: number; 9 | /**重试次数,默认为1,会重试1次 */ 10 | retryCount?: number; 11 | /** 重试间隔 单位毫秒 */ 12 | retryDelay?: number; 13 | preventTimeout?: boolean; 14 | preventAutoDomain?: boolean; 15 | preventJwtToken?: boolean; 16 | preventStatusCode?: boolean; 17 | preventRetry?: boolean; 18 | [key: string]: any; 19 | } 20 | /** 21 | * 请求返回 22 | */ 23 | export interface ResponseData { 24 | statusCode: number; 25 | data: T; 26 | error?: TError; 27 | header: any; 28 | } 29 | export type HttpMethods = "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "TRACE" | "CONNECT"; 30 | export type DefaultIntercepterOptions = { 31 | /** 重试次数 @see RetryIntercepter */ 32 | retryCount?: number; 33 | /** 重试间隔 单位毫秒 */ 34 | retryDelay?: number; 35 | /** 超时(秒) */ 36 | timeout?: number; 37 | /** 最大超时(秒) */ 38 | maxTimeout?: number; 39 | /**通过 @see AutoDomainIntercepter 来添加默认地址 */ 40 | baseUrl?: string; 41 | /** 启用 @see StatusCodeIntercepter */ 42 | statusCodeError?: boolean; 43 | [key: string]: any; 44 | }; 45 | export interface HandlerProfiles { 46 | request: IHttpClientHandler; 47 | upload: IHttpClientHandler; 48 | download: IHttpClientHandler; 49 | } 50 | export interface HttpClientRequestOption { 51 | /**请求地址 */ 52 | url: string; 53 | /** 请求方式 */ 54 | method?: HttpMethods; 55 | /** Post 或者 Get 的数据 */ 56 | data?: Record | string; 57 | /** http header */ 58 | header?: Record; 59 | /** 响应数据的类型和方式 */ 60 | responseType?: "text" | "arraybuffer"; 61 | /** 拦截器管道数据和配置 */ 62 | pipeOptions?: PipeOptions; 63 | } 64 | export interface HttpClientGetOption extends HttpClientRequestOption { 65 | method?: 'GET'; 66 | } 67 | export interface HttpClientPostOption extends HttpClientRequestOption { 68 | method?: 'POST'; 69 | } 70 | export interface HttpClientPutOption extends HttpClientRequestOption { 71 | method?: 'PUT'; 72 | } 73 | export interface HttpClientDeleteOption extends HttpClientRequestOption { 74 | method?: 'DELETE'; 75 | } 76 | export interface HttpClientUploadOption extends HttpClientRequestOption { 77 | method?: 'POST'; 78 | data: HttpClientUploadData; 79 | } 80 | export interface HttpClientUploadData { 81 | files?: { 82 | name: string; 83 | uri: string; 84 | }[]; 85 | fileType?: "image" | "audio" | "video"; 86 | filePath?: string; 87 | name?: string; 88 | formData?: any; 89 | [k: string]: any; 90 | } 91 | export interface HttpClientDownloadOption extends HttpClientRequestOption { 92 | data: undefined; 93 | } 94 | -------------------------------------------------------------------------------- /demo/demo/src/intercepter.ts: -------------------------------------------------------------------------------- 1 | import { CancelError, HttpClientIntercepter, IntercepterDelegate, IntercepterRequestContext, IntercepterResponseContext, StatusCodeError } from "uni-httpclient"; 2 | 3 | export class MyAuthIntercepter implements HttpClientIntercepter{ 4 | async handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 5 | // 演示如何自定义拦截器 6 | var rnd = Math.random() * 10; 7 | request.header['abc'] = '123'; 8 | // 这里演示如何利用pipeOption 跟拦截器通信 9 | if(request.pipeOptions.useMyAuth == true && rnd > 5){ 10 | // 只有当配置了 useMyAuth:true 的时候, 我们才根据我们的规则进行 11 | // 如果 rnd 比5大, 则我们当不会发送请求, 而是返回我们的返回值; 12 | return { 13 | statusCode:200, 14 | data: { rnd: rnd }, // 因为是 200, 所以data会返回 15 | httpClient: undefined, 16 | httpClientHander:undefined, 17 | header:{}, 18 | pipeOptions:request.pipeOptions 19 | } 20 | 21 | // 如果您不想返回任何信息,可以 直接 throw 一个Error 22 | // 比如; 23 | //throw new StatusCodeError(401); 24 | } 25 | 26 | // 此行之前都是 前拦截 27 | const result = await next(request); // 这里是关键, 如果您想让它继续执行,您必须调用 next() 28 | // 此行以后都是 后拦截 29 | result.data = { ...result.data, abc:rnd }; // 这个例子是给 data 增加一个 abc属性 30 | 31 | // 返回我们的响应 32 | return result; 33 | } 34 | 35 | } 36 | 37 | // 这个代码您可以直接拿去修改一下,直接用 38 | export class GlobalErrorIntercepter implements HttpClientIntercepter{ 39 | async handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 40 | try{ 41 | return await next(request); 42 | } 43 | catch(e){ 44 | if(e instanceof CancelError){ 45 | uni.showToast({ 46 | title: '您的请求取消了', 47 | icon: 'none' 48 | }) 49 | } 50 | else if(e instanceof StatusCodeError){ 51 | if(e.statusCode == 401){ 52 | // 这里应该去登录 53 | // uni.reLaunch({ url: '/pages/login' }) 54 | //我们这里模拟一下就好了 55 | uni.showModal({ 56 | content: '您应该去登录了', 57 | showCancel: false 58 | }) 59 | } 60 | else if( e.statusCode == 403){ 61 | uni.showModal({ 62 | content: '您没有权限啊', 63 | showCancel: false 64 | }) 65 | } 66 | 67 | else{ 68 | uni.showModal({ 69 | content: 'http状态码错误:' + e.statusCode, 70 | showCancel: false 71 | }) 72 | } 73 | } 74 | else{ 75 | uni.showToast({ 76 | title: '未知的错误呢', 77 | icon: 'none' 78 | }) 79 | } 80 | 81 | throw e; // 确保错误被抛出 82 | } 83 | } 84 | 85 | } -------------------------------------------------------------------------------- /src/options.ts: -------------------------------------------------------------------------------- 1 | import type { ICancelToken } from './cancel-token'; 2 | import type { IHttpClientHandler } from './httpclien-handler'; 3 | 4 | export interface PipeOptions { 5 | cancelToken?: ICancelToken; 6 | /** 秒数, 必须添加 @see TimeoutIntercepter 才管用 */ 7 | timeout?: number; 8 | /** 秒数,必须添加 @see MaxTimeoutIntercepter 才管用 */ 9 | maxTimeout?:number; 10 | /**重试次数,默认为1,会重试1次 */ 11 | retryCount?:number; 12 | /** 重试间隔 单位毫秒 */ 13 | retryDelay?:number; 14 | preventTimeout?: boolean; 15 | preventAutoDomain?: boolean; 16 | preventJwtToken?: boolean; 17 | preventStatusCode?: boolean; 18 | preventRetry?:boolean; 19 | [key: string]: any; 20 | } 21 | 22 | /** 23 | * 请求返回 24 | */ 25 | export interface ResponseData { 26 | statusCode: number; 27 | data: T; 28 | error?: TError; 29 | header: any; 30 | } 31 | 32 | export type HttpMethods = "OPTIONS" 33 | | "GET" 34 | | "HEAD" 35 | | "POST" 36 | | "PUT" 37 | | "DELETE" 38 | | "TRACE" 39 | | "CONNECT"; 40 | 41 | 42 | export type DefaultIntercepterOptions = { 43 | /** 重试次数 @see RetryIntercepter */ 44 | retryCount?:number; 45 | /** 重试间隔 单位毫秒 */ 46 | retryDelay?:number; 47 | /** 超时(秒) */ 48 | timeout?:number; 49 | /** 最大超时(秒) */ 50 | maxTimeout?:number; 51 | /**通过 @see AutoDomainIntercepter 来添加默认地址 */ 52 | baseUrl?:string; 53 | /** 启用 @see StatusCodeIntercepter */ 54 | statusCodeError?:boolean; 55 | 56 | [key:string]:any; 57 | } 58 | 59 | export interface HandlerProfiles{ 60 | request: IHttpClientHandler; 61 | upload:IHttpClientHandler; 62 | download:IHttpClientHandler; 63 | } 64 | 65 | export interface HttpClientRequestOption{ 66 | /**请求地址 */ 67 | url:string; 68 | /** 请求方式 */ 69 | method?:HttpMethods; 70 | /** Post 或者 Get 的数据 */ 71 | data?:Record | string; 72 | /** http header */ 73 | header?:Record; 74 | /** 响应数据的类型和方式 */ 75 | responseType?:"text" | "arraybuffer"; 76 | /** 拦截器管道数据和配置 */ 77 | pipeOptions?:PipeOptions; 78 | } 79 | export interface HttpClientGetOption extends HttpClientRequestOption{ 80 | method?:'GET' 81 | } 82 | export interface HttpClientPostOption extends HttpClientRequestOption{ 83 | method?:'POST' 84 | } 85 | export interface HttpClientPutOption extends HttpClientRequestOption{ 86 | method?:'PUT' 87 | } 88 | export interface HttpClientDeleteOption extends HttpClientRequestOption{ 89 | method?:'DELETE' 90 | } 91 | 92 | export interface HttpClientUploadOption extends HttpClientRequestOption{ 93 | method?:'POST'; 94 | data: HttpClientUploadData 95 | } 96 | 97 | export interface HttpClientUploadData{ 98 | files?: { name: string; uri: string }[]; 99 | fileType?: "image" | "audio" | "video"; 100 | filePath?: string; 101 | name?: string; 102 | formData?: any; 103 | [k:string]:any; 104 | } 105 | 106 | export interface HttpClientDownloadOption extends HttpClientRequestOption{ 107 | data:undefined; 108 | } 109 | -------------------------------------------------------------------------------- /demo/demo/src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "appid": "", 4 | "description": "", 5 | "versionName": "1.0.0", 6 | "versionCode": "100", 7 | "transformPx":false, 8 | "app-plus": { /* 5+App特有相关 */ 9 | "modules": { /* 模块配置 */ 10 | 11 | }, 12 | "distribute": { /* 应用发布信息 */ 13 | "android": { /* android打包配置 */ 14 | "permissions": ["", 15 | "", 16 | "", 17 | "", 18 | "", 19 | "", 20 | "", 21 | "", 22 | "", 23 | "", 24 | "", 25 | "", 26 | "", 27 | "", 28 | "", 29 | "", 30 | "", 31 | "", 32 | "", 33 | "", 34 | "", 35 | "" 36 | ] 37 | }, 38 | "ios": { /* ios打包配置 */ 39 | 40 | }, 41 | "sdkConfigs": { /* SDK配置 */ 42 | 43 | } 44 | }, 45 | "usingComponents":true 46 | }, 47 | "quickapp": { /* 快应用特有相关 */ 48 | 49 | }, 50 | "mp-weixin": { /* 小程序特有相关 */ 51 | "usingComponents":true, 52 | "appid": "", 53 | "setting" : { 54 | "urlCheck" : true 55 | } 56 | }, 57 | "mp-alipay" : { 58 | "usingComponents" : true 59 | }, 60 | "mp-baidu" : { 61 | "usingComponents" : true 62 | }, 63 | "mp-toutiao" : { 64 | "usingComponents" : true 65 | }, 66 | "mp-qq" : { 67 | "usingComponents" : true 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/token-storages/token-storage.ts: -------------------------------------------------------------------------------- 1 | export class TokenStorage { 2 | constructor(private tokenType:string){ 3 | 4 | } 5 | expireOffsetMs = -5000; 6 | private readonly cChar = "#"; 7 | private readonly akey = "Authentication"; 8 | 9 | private getKey(domain: string) { 10 | return `${this.akey}${this.cChar}${this.tokenType}${this.cChar}${domain}`; 11 | } 12 | 13 | isTokenExpired(domain:string){ 14 | if (domain == null || domain == "") { 15 | throw new Error("domain can not be null or empty, but you can use '*' "); 16 | } 17 | let token = this.getToken(domain); 18 | return token == null; 19 | } 20 | 21 | getToken(domain: string, includeExpired?: boolean): string | null { 22 | if (domain == null) { 23 | throw new Error("domain can not be null or empty, but you can use '*'"); 24 | } 25 | const key = this.getKey(domain); 26 | var info = uni.getStorageSync(key) as TokenInfo; 27 | if(info == null){ 28 | return null; 29 | } 30 | if(includeExpired !== true){ 31 | const epTime = info.expireAt + this.expireOffsetMs; 32 | const epDate = new Date(epTime); 33 | if(new Date() > epDate){ 34 | return null; 35 | } 36 | } 37 | return info.token; 38 | } 39 | 40 | /** 41 | * async 允许你挂载 onTokenExpired 钩子函数 42 | */ 43 | getTokenAsync(domain:string):Promise{ 44 | let t = this.getToken(domain); 45 | if(t == null){ 46 | if(this.onTokenExpired!=null){ 47 | return this.onTokenExpired(this,domain) 48 | .then(()=>this.getToken(domain)); 49 | } 50 | } 51 | return new Promise((resove,reject)=>{ 52 | resove(this.getToken(domain)); 53 | }) 54 | } 55 | 56 | /** 57 | * 设置token 58 | * @param domain 域名, 你可以设置 '*' 但不能是null 59 | * @param expireIn 秒 60 | */ 61 | setToken(domain: string, token: string, expireIn: number) { 62 | if (domain == null) { 63 | throw new Error("domain can not be null or empty, but you can use '*'"); 64 | } 65 | const key = this.getKey(domain); 66 | const cTime = new Date().getTime(); 67 | const eTime = cTime + expireIn * 1000; 68 | const info: TokenInfo = { 69 | storageAt: cTime, 70 | expireAt: eTime, 71 | token: token, 72 | }; 73 | uni.setStorageSync(key, info); 74 | } 75 | 76 | clearToken(domain:string){ 77 | if (domain == null) { 78 | throw new Error("domain can not be null or empty, but you can use '*'"); 79 | } 80 | const key = this.getKey(domain); 81 | uni.removeStorageSync(key); 82 | } 83 | 84 | onTokenExpired?: (storage:TokenStorage, domain:string)=>Promise; 85 | } 86 | 87 | interface TokenInfo { 88 | /**ms */ 89 | storageAt: number; 90 | /**ms */ 91 | expireAt: number; 92 | token: string; 93 | } 94 | 95 | export const tokenStorage = new TokenStorage("access_token"); 96 | export const freshTokenStorage = new TokenStorage("fresh_token"); 97 | -------------------------------------------------------------------------------- /src/cancel-token.ts: -------------------------------------------------------------------------------- 1 | // 我尝试复刻 C# 里面的 CancellationToken 和 CancellationTokenSource, 发现 C# 之所以分离这两个,有一部分是设计原则的问题, 2 | // 还有一个就是 CancellationToken 是一个 struct , 它永远不会变成null, 但这在 ts/js 中是无法实现的,所以混合这两者的功能,以便更方面的调用, 3 | // 但是从原则来讲,使用token 的一方, 不应该调用任何跟 Cancel相关的主动方法, 请看 ICancelToken 和 ICancelSource 4 | 5 | import { CancelError } from './errors'; 6 | 7 | /** 8 | * a CancelToken that support safe cancellation 9 | */ 10 | export class CancelToken implements ICancelSource, ICancelToken { 11 | constructor(); 12 | constructor(token: CancelToken); 13 | constructor(token: ICancelToken); 14 | constructor(afterms: number); 15 | constructor(option?: number | ICancelToken) { 16 | if (typeof option === "number") { 17 | this.cancelAfter(option); 18 | } 19 | else if (option == null) { 20 | return; 21 | } 22 | else { 23 | try { 24 | option.register(x => this.cancel()); 25 | } 26 | catch (e) { 27 | throw new Error(`argument must be a instace of interface ICancelToken or class CancelToken : ${e}`) 28 | } 29 | } 30 | 31 | } 32 | 33 | isCanceled: boolean = false; 34 | 35 | 36 | throwIfCanceled() { 37 | if (this.isCanceled) { 38 | throw new CancelError() 39 | } 40 | } 41 | 42 | linkToken(token: CancelToken): void; 43 | linkToken(token: ICancelToken): void; 44 | linkToken(token: ICancelToken): void { 45 | token.register(x => this.cancel()); 46 | } 47 | 48 | private _t?: number; 49 | 50 | cancelAfter(timems: number) { 51 | clearTimeout(this._t); 52 | this._t = setTimeout(() => { 53 | this.cancel(); 54 | }, timems); 55 | return this; 56 | } 57 | 58 | stopCancel() { 59 | clearTimeout(this._t); 60 | return this; 61 | } 62 | 63 | cancel() { 64 | if (this.isCanceled == false) { 65 | this.isCanceled = true; 66 | this.triggerAction(); 67 | } 68 | } 69 | 70 | private _actions: Array<(sender: CancelToken) => any> = []; 71 | 72 | private triggerAction() { 73 | while (this._actions.length > 0) { 74 | let act = this._actions.shift(); 75 | act?.(this); 76 | } 77 | } 78 | 79 | register(action: (sender: CancelToken) => any) { 80 | this._actions.push(action); 81 | if (this.isCanceled) { 82 | // already canceled , so only trigger cancel 83 | this.triggerAction(); // after trigger the action will be remove 84 | } 85 | return this; 86 | } 87 | 88 | getToken(): CancelToken; 89 | getToken(): ICancelToken { 90 | return this; 91 | } 92 | } 93 | 94 | 95 | export interface ICancelSource { 96 | cancelAfter(timems: number): ICancelSource; 97 | cancel(): void; 98 | stopCancel(): ICancelSource; 99 | linkToken(token: ICancelToken): void; 100 | getToken(): ICancelToken; 101 | } 102 | 103 | export interface ICancelToken { 104 | isCanceled: boolean; 105 | throwIfCanceled(): void; 106 | register(action: (sender: ICancelToken) => any): ICancelToken 107 | } 108 | -------------------------------------------------------------------------------- /dist/httpclient.d.ts: -------------------------------------------------------------------------------- 1 | import type { IntercepterRequestContext } from './intercepter'; 2 | import type { PipeOptions, ResponseData, HttpMethods, DefaultIntercepterOptions, HandlerProfiles, HttpClientGetOption, HttpClientRequestOption, HttpClientPostOption, HttpClientPutOption, HttpClientUploadOption } from './options'; 3 | import type { IHttpClientHandler } from './httpclien-handler'; 4 | import { IntercepterCollection } from './IntercepterCollection'; 5 | export declare class HttpClient { 6 | private profiles; 7 | readonly intercepters: IntercepterCollection; 8 | /** 9 | * 构建一个 @see HttpClient 对象 10 | * @param profiles 一个处理程序的配置对象 11 | */ 12 | constructor(profiles?: HandlerProfiles); 13 | setupDefaults(options?: DefaultIntercepterOptions): void; 14 | /** 15 | * 设置 默认实例 @see httpclient 的拦截器 16 | * @param option 拦截器配置 17 | * @deprecated 建议直接调用实例的该方法 18 | */ 19 | static setupDefaults(options?: DefaultIntercepterOptions): void; 20 | get(url: string, query?: object | string, header?: any, options?: { 21 | responseType?: "text" | "arraybuffer"; 22 | }, pipeOptions?: PipeOptions): Promise; 23 | get(option: HttpClientGetOption): Promise; 24 | post(url: string, data?: object | string, header?: any, options?: { 25 | responseType?: "text" | "arraybuffer"; 26 | }, pipeOptions?: PipeOptions): Promise; 27 | post(option: HttpClientPostOption): Promise; 28 | put(url: string, data: object | string, header?: any, options?: { 29 | responseType?: "text" | "arraybuffer"; 30 | }, pipeOptions?: PipeOptions): Promise; 31 | put(option: HttpClientPutOption): Promise; 32 | form(url: string, data: object | string, header?: any, options?: { 33 | responseType?: "text" | "arraybuffer"; 34 | }, pipeOptions?: PipeOptions): Promise; 35 | form(option: HttpClientPostOption): Promise; 36 | delete(url: string, data?: object | string, header?: any, options?: { 37 | responseType?: "text" | "arraybuffer"; 38 | }, pipeOptions?: PipeOptions): Promise; 39 | delete(option: HttpClientPutOption): Promise; 40 | uploadFile(url: string, data: { 41 | files?: { 42 | name: string; 43 | uri: string; 44 | }[]; 45 | fileType?: "image" | "audio" | "video"; 46 | filePath?: string; 47 | name?: string; 48 | formData?: any; 49 | }, header?: any, pipeOptions?: PipeOptions): Promise>; 50 | uploadFile(optoin: HttpClientUploadOption): Promise>; 51 | download(url: string, header?: any, options?: { 52 | responseType?: "text" | "arraybuffer"; 53 | }, pipeOptions?: PipeOptions): Promise>; 54 | download(): Promise>; 55 | request(url: string, method: HttpMethods, data?: any, header?: any, options?: { 56 | responseType?: "text" | "arraybuffer"; 57 | }, pipeOptions?: PipeOptions): Promise>; 58 | request(option: HttpClientRequestOption): Promise>; 59 | send(request: IntercepterRequestContext | { 60 | pipeOptions?: PipeOptions; 61 | [k: string]: any; 62 | }, handler: IHttpClientHandler): Promise>; 63 | private createIntercepterPipeline; 64 | } 65 | export declare const httpClient: HttpClient; 66 | -------------------------------------------------------------------------------- /dist/handlers/uni-handler.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"uni-handler.js","sourceRoot":"","sources":["../../src/handlers/uni-handler.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /demo/demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "yarn run dev:h5", 7 | "build": "yarn run build:h5", 8 | "build:app-plus": "cross-env NODE_ENV=production UNI_PLATFORM=app-plus vue-cli-service uni-build", 9 | "build:custom": "cross-env NODE_ENV=production uniapp-cli custom", 10 | "build:h5": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build", 11 | "build:mp-360": "cross-env NODE_ENV=production UNI_PLATFORM=mp-360 vue-cli-service uni-build", 12 | "build:mp-alipay": "cross-env NODE_ENV=production UNI_PLATFORM=mp-alipay vue-cli-service uni-build", 13 | "build:mp-baidu": "cross-env NODE_ENV=production UNI_PLATFORM=mp-baidu vue-cli-service uni-build", 14 | "build:mp-kuaishou": "cross-env NODE_ENV=production UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build", 15 | "build:mp-qq": "cross-env NODE_ENV=production UNI_PLATFORM=mp-qq vue-cli-service uni-build", 16 | "build:mp-toutiao": "cross-env NODE_ENV=production UNI_PLATFORM=mp-toutiao vue-cli-service uni-build", 17 | "build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build", 18 | "build:quickapp-native": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-native vue-cli-service uni-build", 19 | "build:quickapp-webview": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview vue-cli-service uni-build", 20 | "build:quickapp-webview-huawei": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build", 21 | "build:quickapp-webview-union": "cross-env NODE_ENV=production UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build", 22 | "dev:app-plus": "cross-env NODE_ENV=development UNI_PLATFORM=app-plus vue-cli-service uni-build --watch", 23 | "dev:custom": "cross-env NODE_ENV=development uniapp-cli custom", 24 | "dev:h5": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve", 25 | "dev:mp-360": "cross-env NODE_ENV=development UNI_PLATFORM=mp-360 vue-cli-service uni-build --watch", 26 | "dev:mp-alipay": "cross-env NODE_ENV=development UNI_PLATFORM=mp-alipay vue-cli-service uni-build --watch", 27 | "dev:mp-baidu": "cross-env NODE_ENV=development UNI_PLATFORM=mp-baidu vue-cli-service uni-build --watch", 28 | "dev:mp-kuaishou": "cross-env NODE_ENV=development UNI_PLATFORM=mp-kuaishou vue-cli-service uni-build --watch", 29 | "dev:mp-qq": "cross-env NODE_ENV=development UNI_PLATFORM=mp-qq vue-cli-service uni-build --watch", 30 | "dev:mp-toutiao": "cross-env NODE_ENV=development UNI_PLATFORM=mp-toutiao vue-cli-service uni-build --watch", 31 | "dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch", 32 | "dev:quickapp-native": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-native vue-cli-service uni-build --watch", 33 | "dev:quickapp-webview": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview vue-cli-service uni-build --watch", 34 | "dev:quickapp-webview-huawei": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-huawei vue-cli-service uni-build --watch", 35 | "dev:quickapp-webview-union": "cross-env NODE_ENV=development UNI_PLATFORM=quickapp-webview-union vue-cli-service uni-build --watch", 36 | "info": "yarn node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js", 37 | "serve:quickapp-native": "node node_modules/@dcloudio/uni-quickapp-native/bin/serve.js", 38 | "test:android": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=android jest -i", 39 | "test:h5": "cross-env UNI_PLATFORM=h5 jest -i", 40 | "test:ios": "cross-env UNI_PLATFORM=app-plus UNI_OS_NAME=ios jest -i", 41 | "test:mp-baidu": "cross-env UNI_PLATFORM=mp-baidu jest -i", 42 | "test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i" 43 | }, 44 | "dependencies": { 45 | "@dcloudio/uni-app-plus": "^2.0.0-31820210406002", 46 | "@dcloudio/uni-h5": "^2.0.0-31820210406002", 47 | "@dcloudio/uni-helper-json": "1.0.13", 48 | "@dcloudio/uni-mp-360": "^2.0.0-31820210406002", 49 | "@dcloudio/uni-mp-alipay": "^2.0.0-31820210406002", 50 | "@dcloudio/uni-mp-baidu": "^2.0.0-31820210406002", 51 | "@dcloudio/uni-mp-qq": "^2.0.0-31820210406002", 52 | "@dcloudio/uni-mp-toutiao": "^2.0.0-31820210406002", 53 | "@dcloudio/uni-mp-vue": "^2.0.0-31820210406002", 54 | "@dcloudio/uni-mp-weixin": "^2.0.0-31820210406002", 55 | "@dcloudio/uni-quickapp-native": "^2.0.0-31820210406002", 56 | "@dcloudio/uni-quickapp-webview": "^2.0.0-31820210406002", 57 | "@dcloudio/uni-stat": "^2.0.0-31820210406002", 58 | "@vue/shared": "^3.0.11", 59 | "core-js": "^3.10.1", 60 | "flyio": "^0.6.2", 61 | "regenerator-runtime": "^0.13.7", 62 | "uni-httpclient": "link:../../", 63 | "vue": "^2.6.11", 64 | "vue-class-component": "^7.2.6", 65 | "vue-property-decorator": "^9.1.2", 66 | "vuex": "^3.6.2" 67 | }, 68 | "devDependencies": { 69 | "@babel/plugin-syntax-typescript": "^7.12.13", 70 | "@dcloudio/types": "2.1.2", 71 | "@dcloudio/uni-automator": "^2.0.0-31820210406002", 72 | "@dcloudio/uni-cli-shared": "^2.0.0-31820210406002", 73 | "@dcloudio/uni-migration": "^2.0.0-31820210406002", 74 | "@dcloudio/uni-template-compiler": "^2.0.0-31820210406002", 75 | "@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.0-31820210406002", 76 | "@dcloudio/vue-cli-plugin-uni": "^2.0.0-31820210406002", 77 | "@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.0-31820210406002", 78 | "@dcloudio/webpack-uni-mp-loader": "^2.0.0-31820210406002", 79 | "@dcloudio/webpack-uni-pages-loader": "^2.0.0-31820210406002", 80 | "@vue/cli-plugin-babel": "~4.5.12", 81 | "@vue/cli-plugin-typescript": "4.5.12", 82 | "@vue/cli-service": "~4.5.12", 83 | "babel-plugin-import": "^1.13.3", 84 | "cross-env": "^7.0.3", 85 | "jest": "^26.6.3", 86 | "mini-types": "0.1.5", 87 | "miniprogram-api-typings": "3.3.1", 88 | "postcss-comment": "^2.0.0", 89 | "typescript": "^4.2.4", 90 | "vue-template-compiler": "^2.6.11" 91 | }, 92 | "browserslist": [ 93 | "Android >= 4", 94 | "ios >= 8" 95 | ], 96 | "uni-app": { 97 | "scripts": {} 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /dist/url.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"url.js","sourceRoot":"","sources":["../src/url.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/httpclient.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"httpclient.js","sourceRoot":"","sources":["../src/httpclient.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /src/handlers/uni-handler.ts: -------------------------------------------------------------------------------- 1 | import type { IntercepterRequestContext, IntercepterResponseContext } from "../intercepter"; 2 | import type { HttpClient } from '../httpclient'; 3 | import { CancelError } from '../errors'; 4 | import { Task } from '../task/task'; 5 | import type { IHttpClientHandler } from "../httpclien-handler"; 6 | declare let wx:UniApp.Uni; 7 | const app = uni || wx; 8 | 9 | /** uni 的 GET POST PUT OPTION 等操作的 处理终端 */ 10 | export class UniRequestHttpClientHandler implements IHttpClientHandler { 11 | 12 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise { 13 | if (request.pipeOptions?.cancelToken?.isCanceled) { 14 | return Task.fromError(new CancelError()); 15 | } 16 | const p = new Promise((resolve, reject) => { 17 | let task = app.request({ 18 | url: request.url, 19 | method: request.method, 20 | data: request.data, 21 | header: request.header, 22 | responseType: request.responseType ?? "text", 23 | success: x => { 24 | // console.log(x); 25 | // if ( 26 | // (x.header["content-type"] as string).toLowerCase().indexOf("json") > 27 | // -1 28 | // ) { 29 | // x.data = JSON.parse(x.data!) as any; 30 | // } 31 | // uni api automatic do this for us 32 | resolve({ 33 | header: x.header, 34 | statusCode: x.statusCode ?? 200, 35 | data: x.data, 36 | httpClient: httpClient, 37 | httpClientHander: this, 38 | pipeOptions: request.pipeOptions 39 | }); 40 | }, 41 | fail: x => { 42 | if (request.pipeOptions?.cancelToken?.isCanceled) { 43 | reject(new CancelError()); 44 | return; 45 | } 46 | reject(x); 47 | } 48 | }); 49 | 50 | if (request.pipeOptions?.cancelToken) { 51 | let cancelToken = request.pipeOptions.cancelToken; 52 | cancelToken.register(x => task.abort()); 53 | } 54 | }); 55 | 56 | return p; 57 | } 58 | 59 | } 60 | 61 | /** uni 的 上传文件 操作的 处理终端 */ 62 | export class UniUploadHttpClientHandler implements IHttpClientHandler { 63 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise { 64 | if (request.pipeOptions?.cancelToken?.isCanceled) { 65 | return Task.fromError(new CancelError()); 66 | } 67 | const p = new Promise((resovle, reject) => { 68 | let task = app.uploadFile({ 69 | url: request.url, 70 | files: request.data?.files, 71 | fileType: request.data?.fileType, 72 | filePath: request.data?.filePath, 73 | name: request.data?.name, 74 | header: request.header, 75 | formData: request.data?.formData, 76 | 77 | success: x => { 78 | let data = x.data; 79 | let header: { [key: string]: string; } = {}; 80 | //let ct = x2.header?.["Content-Type"] as string; 81 | try { 82 | data = JSON.parse(data!); 83 | header["Content-Type"] = "application/json"; 84 | } catch (e) { 85 | data = data; 86 | // 说明不是json, 操蛋的api没法监测header 87 | } 88 | resovle({ 89 | statusCode: x.statusCode ?? 200, 90 | header: header, 91 | data: data, 92 | httpClient, 93 | httpClientHander: this, 94 | pipeOptions: request.pipeOptions 95 | }); 96 | }, 97 | fail: e => { 98 | if (request.pipeOptions?.cancelToken?.isCanceled) { 99 | reject(new CancelError()); 100 | return; 101 | } 102 | reject(e); 103 | } 104 | }); 105 | 106 | if (request.pipeOptions?.cancelToken) { 107 | let cancelToken = request.pipeOptions.cancelToken; 108 | cancelToken.register(x => task.abort()); 109 | } 110 | }); 111 | return p; 112 | } 113 | 114 | } 115 | 116 | /** uni 的 下载文件 操作的 处理终端 */ 117 | export class UniDownloadHttpClientHandler implements IHttpClientHandler { 118 | send(request: IntercepterRequestContext, httpClient: HttpClient): Promise { 119 | if (request.pipeOptions?.cancelToken?.isCanceled) { 120 | return Task.fromError(new CancelError()); 121 | } 122 | const p = new Promise((resolve, reject) => { 123 | 124 | let task = app.downloadFile({ 125 | url: request.url, 126 | header: request.header, 127 | success: res => { 128 | resolve({ 129 | statusCode: res.statusCode ?? 200, 130 | header: (res as any).header ?? {}, 131 | data: res.tempFilePath, 132 | httpClientHander: this, 133 | httpClient, 134 | pipeOptions: request.pipeOptions 135 | }); 136 | }, 137 | fail: (e) => { 138 | if (request.pipeOptions?.cancelToken?.isCanceled) { 139 | reject(new CancelError()); 140 | return; 141 | } 142 | reject(e); 143 | } 144 | }); 145 | if (request.pipeOptions?.cancelToken) { 146 | let cancelToken = request.pipeOptions.cancelToken; 147 | cancelToken.register(x => task.abort()); 148 | } 149 | }); 150 | return p; 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /dist/handlers/uni-handler.js: -------------------------------------------------------------------------------- 1 | import { CancelError } from '../errors'; 2 | import { Task } from '../task/task'; 3 | const app = uni || wx; 4 | /** uni 的 GET POST PUT OPTION 等操作的 处理终端 */ 5 | export class UniRequestHttpClientHandler { 6 | send(request, httpClient) { 7 | var _a, _b; 8 | if ((_b = (_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 9 | return Task.fromError(new CancelError()); 10 | } 11 | const p = new Promise((resolve, reject) => { 12 | var _a, _b; 13 | let task = app.request({ 14 | url: request.url, 15 | method: request.method, 16 | data: request.data, 17 | header: request.header, 18 | responseType: (_a = request.responseType) !== null && _a !== void 0 ? _a : "text", 19 | success: x => { 20 | var _a; 21 | // console.log(x); 22 | // if ( 23 | // (x.header["content-type"] as string).toLowerCase().indexOf("json") > 24 | // -1 25 | // ) { 26 | // x.data = JSON.parse(x.data!) as any; 27 | // } 28 | // uni api automatic do this for us 29 | resolve({ 30 | header: x.header, 31 | statusCode: (_a = x.statusCode) !== null && _a !== void 0 ? _a : 200, 32 | data: x.data, 33 | httpClient: httpClient, 34 | httpClientHander: this, 35 | pipeOptions: request.pipeOptions 36 | }); 37 | }, 38 | fail: x => { 39 | var _a, _b; 40 | if ((_b = (_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 41 | reject(new CancelError()); 42 | return; 43 | } 44 | reject(x); 45 | } 46 | }); 47 | if ((_b = request.pipeOptions) === null || _b === void 0 ? void 0 : _b.cancelToken) { 48 | let cancelToken = request.pipeOptions.cancelToken; 49 | cancelToken.register(x => task.abort()); 50 | } 51 | }); 52 | return p; 53 | } 54 | } 55 | /** uni 的 上传文件 操作的 处理终端 */ 56 | export class UniUploadHttpClientHandler { 57 | send(request, httpClient) { 58 | var _a, _b; 59 | if ((_b = (_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 60 | return Task.fromError(new CancelError()); 61 | } 62 | const p = new Promise((resovle, reject) => { 63 | var _a, _b, _c, _d, _e, _f; 64 | let task = app.uploadFile({ 65 | url: request.url, 66 | files: (_a = request.data) === null || _a === void 0 ? void 0 : _a.files, 67 | fileType: (_b = request.data) === null || _b === void 0 ? void 0 : _b.fileType, 68 | filePath: (_c = request.data) === null || _c === void 0 ? void 0 : _c.filePath, 69 | name: (_d = request.data) === null || _d === void 0 ? void 0 : _d.name, 70 | header: request.header, 71 | formData: (_e = request.data) === null || _e === void 0 ? void 0 : _e.formData, 72 | success: x => { 73 | var _a; 74 | let data = x.data; 75 | let header = {}; 76 | //let ct = x2.header?.["Content-Type"] as string; 77 | try { 78 | data = JSON.parse(data); 79 | header["Content-Type"] = "application/json"; 80 | } 81 | catch (e) { 82 | data = data; 83 | // 说明不是json, 操蛋的api没法监测header 84 | } 85 | resovle({ 86 | statusCode: (_a = x.statusCode) !== null && _a !== void 0 ? _a : 200, 87 | header: header, 88 | data: data, 89 | httpClient, 90 | httpClientHander: this, 91 | pipeOptions: request.pipeOptions 92 | }); 93 | }, 94 | fail: e => { 95 | var _a, _b; 96 | if ((_b = (_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 97 | reject(new CancelError()); 98 | return; 99 | } 100 | reject(e); 101 | } 102 | }); 103 | if ((_f = request.pipeOptions) === null || _f === void 0 ? void 0 : _f.cancelToken) { 104 | let cancelToken = request.pipeOptions.cancelToken; 105 | cancelToken.register(x => task.abort()); 106 | } 107 | }); 108 | return p; 109 | } 110 | } 111 | /** uni 的 下载文件 操作的 处理终端 */ 112 | export class UniDownloadHttpClientHandler { 113 | send(request, httpClient) { 114 | var _a, _b; 115 | if ((_b = (_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 116 | return Task.fromError(new CancelError()); 117 | } 118 | const p = new Promise((resolve, reject) => { 119 | var _a; 120 | let task = app.downloadFile({ 121 | url: request.url, 122 | header: request.header, 123 | success: res => { 124 | var _a, _b; 125 | resolve({ 126 | statusCode: (_a = res.statusCode) !== null && _a !== void 0 ? _a : 200, 127 | header: (_b = res.header) !== null && _b !== void 0 ? _b : {}, 128 | data: res.tempFilePath, 129 | httpClientHander: this, 130 | httpClient, 131 | pipeOptions: request.pipeOptions 132 | }); 133 | }, 134 | fail: (e) => { 135 | var _a, _b; 136 | if ((_b = (_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) === null || _b === void 0 ? void 0 : _b.isCanceled) { 137 | reject(new CancelError()); 138 | return; 139 | } 140 | reject(e); 141 | } 142 | }); 143 | if ((_a = request.pipeOptions) === null || _a === void 0 ? void 0 : _a.cancelToken) { 144 | let cancelToken = request.pipeOptions.cancelToken; 145 | cancelToken.register(x => task.abort()); 146 | } 147 | }); 148 | return p; 149 | } 150 | } 151 | //# sourceMappingURL=uni-handler.js.map -------------------------------------------------------------------------------- /src/url.ts: -------------------------------------------------------------------------------- 1 | export class Url { 2 | constructor(url?: string) { 3 | if (url == null) { 4 | return; 5 | } 6 | let pos = 0; 7 | if (url.indexOf('://') > 0) { 8 | pos = url.indexOf('://'); 9 | this.scheme = url.substr(0, pos); 10 | pos += 3; 11 | 12 | if (url.indexOf('/', pos + 1) >= 0) { 13 | this.host = url.substring(pos, url.indexOf('/', pos + 1)); 14 | pos = url.indexOf('/', pos + 1); 15 | } 16 | else { 17 | this.host = url.substring(pos); 18 | pos = url.length; 19 | } 20 | } 21 | this.pathAndQuery = url.substr(pos); 22 | 23 | } 24 | 25 | /** `http` or `https` */ 26 | scheme?: string; 27 | 28 | domain?: string | null; 29 | port?: number | null; 30 | /** domain + port */ 31 | get host(): string | null { 32 | let h = this.domain; 33 | if (this.port != null && !isNaN(this.port)) { 34 | h = h + ':' + this.port; 35 | } 36 | return h ?? null; 37 | } 38 | set host(h: string | null) { 39 | if (h == null) { 40 | this.domain = null; 41 | this.port = null; 42 | return; 43 | } 44 | 45 | const c = countSymble(h, ':'); 46 | if (c === 1 || h.lastIndexOf(']') >= 0) { 47 | // [ipv4 or ipv6 or domain] + port 48 | const pos = h.lastIndexOf(':'); 49 | this.domain = h.substring(0, pos); 50 | this.port = parseInt(h.substring(pos + 1), 10); 51 | } 52 | else { 53 | // no port 54 | this.domain = h; 55 | this.port = null; 56 | } 57 | 58 | function countSymble(str: string, symble: string): number { 59 | let pos = 0; 60 | let ct = 0; 61 | while (str.indexOf(symble, pos) >= 0) { 62 | pos = str.indexOf(symble, pos); 63 | pos += 1; 64 | ct += 1; 65 | } 66 | return ct; 67 | } 68 | } 69 | get pathAndQuery(): string | null { 70 | if (this.path == null && this.queryString == null) { 71 | return null; 72 | } 73 | 74 | return `${this.path ?? ''}${this.queryString ?? ''}`; 75 | } 76 | set pathAndQuery(value: string | null) { 77 | this.parsePathAndQuery(value); 78 | } 79 | #path?: string | null; 80 | get path(): string | null { 81 | if (this.#path == null || this.#path === '') { 82 | return null; 83 | } 84 | if (!this.#path.startsWith('/')) { 85 | return `/${this.#path}`; 86 | } 87 | return this.#path; 88 | } 89 | set path(path: string | null) { 90 | if (path == null || path === '') { 91 | this.#path = null; 92 | return; 93 | } 94 | if (!path.startsWith('/')) { 95 | path = '/' + path; 96 | } 97 | this.#path = path; 98 | } 99 | 100 | get queryString(): string | null { 101 | if (this.query == null) { 102 | return null; 103 | } 104 | const list = []; 105 | for (const name in this.query) { 106 | if (typeof this.query[name] === 'function') { 107 | continue; 108 | } 109 | const kv = [encodeURIComponent(name), encodeURIComponent(this.query[name])].join('='); 110 | list.push(kv); 111 | } 112 | if (list.length === 0) { 113 | return null; 114 | } 115 | return `?${list.join('&')}`; 116 | } 117 | 118 | set queryString(v: string | null) { 119 | if (v == null) { 120 | return; 121 | } 122 | this.parseQuery(v); 123 | } 124 | query?: Record | null; 125 | 126 | get hasQuery(): boolean { 127 | if (this.query != null && Object.getOwnPropertyNames(this.query).length > 0) { 128 | return true; 129 | } 130 | return false; 131 | } 132 | 133 | get isAbsolute(): boolean { 134 | return this.scheme != null && this.scheme !== ''; 135 | } 136 | 137 | get isEmpty(): boolean { 138 | return this.scheme == null && this.host == null && this.pathAndQuery == null; 139 | } 140 | 141 | get isQuery(): boolean { 142 | return this.scheme == null && this.host == null && this.path == null && this.hasQuery; 143 | } 144 | 145 | toString(): string { 146 | if (this.isAbsolute) { 147 | return `${this.scheme}://${this.host}${this.path == null && this.hasQuery ? '/' : ''}${this.pathAndQuery ?? ''}`; 148 | } 149 | return this.pathAndQuery ?? ''; 150 | } 151 | 152 | private parsePathAndQuery(v: string | null): void { 153 | if (v == null) { 154 | this.path = null; 155 | this.query = null; 156 | return; 157 | } 158 | const pos = v.indexOf('?'); 159 | if (pos >= 0) { 160 | this.path = v.substring(0, pos); 161 | this.queryString = v.substring(pos); 162 | } 163 | else { 164 | this.path = v; 165 | } 166 | } 167 | 168 | private parseQuery(queryString: string): void { 169 | if (queryString == null) { 170 | return; 171 | } 172 | if (queryString.startsWith('?')) { 173 | queryString = queryString.substr(1); 174 | } 175 | const kvpair = queryString.split('&'); 176 | if (kvpair.length > 0) { 177 | this.query = {}; 178 | for (const v of kvpair) { 179 | const pos = v.indexOf('='); 180 | if (pos < 0) { 181 | return; 182 | } 183 | this.query[decodeURIComponent(v.substr(0, pos))] = decodeURIComponent(v.substr(pos + 1)); 184 | } 185 | } 186 | else { 187 | this.query = null; 188 | } 189 | 190 | } 191 | 192 | /** return a new Url */ 193 | public add(url: Url): Url { 194 | if (url.isAbsolute) { 195 | return url.clone(); 196 | } 197 | if (this.hasQuery) { 198 | if (url.isQuery) { 199 | const u = this.clone(); 200 | u.query ??= {}; 201 | for (const name in url.query) { 202 | if (url.query.hasOwnProperty(name)) { 203 | u.query[name] = url.query[name]; 204 | } 205 | 206 | } 207 | return u; 208 | } 209 | else { 210 | return url.clone(); 211 | } 212 | } 213 | else { 214 | let thisUrl = this.toString(); 215 | let afterUrl = url.toString(); 216 | if (thisUrl.endsWith('/')) { 217 | thisUrl = thisUrl.substr(0, thisUrl.length - 1); 218 | } 219 | if (!afterUrl.startsWith('/')) { 220 | afterUrl = '/' + afterUrl; 221 | } 222 | return new Url(`${thisUrl}${afterUrl}`); 223 | } 224 | } 225 | 226 | public clone(): Url { 227 | return new Url(this.toString()); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb 341 | 342 | .DS_Store 343 | node_modules/ 344 | unpackage/ 345 | # dist/ 346 | 347 | # local env files 348 | .env.local 349 | .env.*.local 350 | 351 | # Log files 352 | npm-debug.log* 353 | yarn-debug.log* 354 | yarn-error.log* 355 | 356 | # Editor directories and files 357 | .project 358 | .idea 359 | .vscode 360 | *.suo 361 | *.ntvs* 362 | *.njsproj 363 | *.sln 364 | *.sw* 365 | -------------------------------------------------------------------------------- /dist/httpclient.js: -------------------------------------------------------------------------------- 1 | import { AutoDomainIntercepter } from './intercepters/auto-domain-intercepter'; 2 | import { RetryIntercepter } from './intercepters/retry-intercepter'; 3 | import { TimeoutIntercepter } from './intercepters/timeout-interceper'; 4 | import { StatusCodeIntercepter } from './intercepters/statuscode-intercepter'; 5 | import { MaxTimeoutIntercepter } from './intercepters/max-timeout-intercepter'; 6 | import { defaultProfile } from './profiles/default-profile'; 7 | import { IntercepterCollection } from './IntercepterCollection'; 8 | export class HttpClient { 9 | /** 10 | * 构建一个 @see HttpClient 对象 11 | * @param profiles 一个处理程序的配置对象 12 | */ 13 | constructor(profiles) { 14 | this.intercepters = new IntercepterCollection(); 15 | if (profiles == null) { 16 | profiles = defaultProfile; 17 | } 18 | this.profiles = profiles; 19 | } 20 | setupDefaults(options) { 21 | if ((options === null || options === void 0 ? void 0 : options.baseUrl) != null) { 22 | this.intercepters.push(new AutoDomainIntercepter(url => options.baseUrl)); 23 | } 24 | if ((options === null || options === void 0 ? void 0 : options.maxTimeout) != null) { 25 | this.intercepters.push(new MaxTimeoutIntercepter(options.maxTimeout)); 26 | } 27 | if ((options === null || options === void 0 ? void 0 : options.retryCount) != null && (options === null || options === void 0 ? void 0 : options.retryCount) > 0) { 28 | this.intercepters.push(new RetryIntercepter(options.retryCount, options === null || options === void 0 ? void 0 : options.retryDelay)); 29 | } 30 | if ((options === null || options === void 0 ? void 0 : options.timeout) != null) { 31 | this.intercepters.push(new TimeoutIntercepter(options.timeout)); 32 | } 33 | if ((options === null || options === void 0 ? void 0 : options.statusCodeError) == true) { 34 | this.intercepters.push(new StatusCodeIntercepter()); 35 | } 36 | } 37 | /** 38 | * 设置 默认实例 @see httpclient 的拦截器 39 | * @param option 拦截器配置 40 | * @deprecated 建议直接调用实例的该方法 41 | */ 42 | static setupDefaults(options) { 43 | httpClient.setupDefaults(options); 44 | } 45 | get(...args) { 46 | let option; 47 | if (args.length == 1 && typeof (args[0]) !== "string") { 48 | option = args[0]; 49 | } 50 | else { 51 | let [url, data, header, options, pipeOptions] = args; 52 | option = Object.assign(Object.assign({ url, 53 | data, 54 | header }, options), { pipeOptions }); 55 | } 56 | option.method = "GET"; 57 | return this.request(option) 58 | .then(x => x.data); 59 | } 60 | post(...args) { 61 | let option; 62 | if (args.length == 1 && typeof (args[0]) !== "string") { 63 | option = args[0]; 64 | } 65 | else { 66 | let [url, query, header, options, pipeOptions] = args; 67 | option = Object.assign(Object.assign({ url, data: query, header }, options), { pipeOptions }); 68 | } 69 | option.method = "POST"; 70 | return this.request(option) 71 | .then(x => x.data); 72 | } 73 | put(...args) { 74 | let option; 75 | if (args.length == 1 && typeof (args[0]) !== "string") { 76 | option = args[0]; 77 | } 78 | else { 79 | let [url, data, header, options, pipeOptions] = args; 80 | option = Object.assign(Object.assign({ url, 81 | data, 82 | header }, options), { pipeOptions }); 83 | } 84 | option.method = "PUT"; 85 | return this.request(option) 86 | .then(x => x.data); 87 | } 88 | form(...args) { 89 | let option; 90 | if (args.length == 1 && typeof (args[0]) !== "string") { 91 | option = args[0]; 92 | } 93 | else { 94 | let [url, data, header, options, pipeOptions] = args; 95 | option = Object.assign(Object.assign({ url, 96 | data, 97 | header }, options), { pipeOptions }); 98 | } 99 | option.method = "POST"; 100 | option.header = Object.assign(Object.assign({}, option.header), { "Content-Type": "application/x-www-form-urlencoded" }); 101 | return this.request(option) 102 | .then(x => x.data); 103 | } 104 | delete(...args) { 105 | let option; 106 | if (args.length == 1 && typeof (args[0]) !== "string") { 107 | option = args[0]; 108 | } 109 | else { 110 | let [url, data, header, options, pipeOptions] = args; 111 | option = Object.assign(Object.assign({ url, 112 | data, 113 | header }, options), { pipeOptions }); 114 | } 115 | option.method = "DELETE"; 116 | return this.request(option) 117 | .then(x => x.data); 118 | } 119 | uploadFile(...args) { 120 | let option; 121 | if (args.length == 1 && typeof (args[0]) !== "string") { 122 | option = args[0]; 123 | } 124 | else { 125 | let [url, data, header, pipeOptions] = args; 126 | option = { 127 | url, 128 | data, 129 | header, 130 | pipeOptions, 131 | }; 132 | } 133 | option.method = "POST"; 134 | return this.send(option, this.profiles.upload); 135 | } 136 | download(...args) { 137 | var _a; 138 | let option; 139 | if (args.length == 1 && typeof (args[0]) !== "string") { 140 | option = args[0]; 141 | } 142 | else { 143 | let [url, header, options, pipeOptions] = args; 144 | option = Object.assign(Object.assign({ url, 145 | header }, options), { pipeOptions }); 146 | } 147 | (_a = option.method) !== null && _a !== void 0 ? _a : (option.method = "GET"); 148 | return this.send(option, this.profiles.download); 149 | } 150 | /** 151 | * 全能的请求 152 | * @param url 地址 153 | * @param method 方法 154 | * @param data 数据 155 | * @param header 请求头 156 | * @param options 其他参数 157 | */ 158 | request(...args) { 159 | if (args.length == 1 && typeof (args[0]) !== "string") { 160 | const op = args[0]; 161 | return this.send(op, this.profiles.request); 162 | } 163 | let [url, method, data, header, options, pipeOptions] = args; 164 | return this.send(Object.assign(Object.assign({ url, 165 | method, 166 | data, 167 | header }, options), { pipeOptions }), this.profiles.request); 168 | } 169 | send(request, handler) { 170 | var _a, _b; 171 | let pipeline = this.createIntercepterPipeline(handler); 172 | (_a = request.header) !== null && _a !== void 0 ? _a : (request.header = {}); 173 | (_b = request.pipeOptions) !== null && _b !== void 0 ? _b : (request.pipeOptions = {}); 174 | return pipeline(request); 175 | } 176 | createIntercepterPipeline(handler) { 177 | let client = this; 178 | class HandlerIntercepter { 179 | constructor(handler, client) { 180 | this.handler = handler; 181 | this.client = client; 182 | } 183 | handle(request, next) { 184 | return this.handler.send(request, this.client); 185 | } 186 | } 187 | let delegate = (req) => new HandlerIntercepter(handler, client).handle(req, null); 188 | for (let i of [...this.intercepters].reverse()) { 189 | let func = (x) => ((req) => i.handle(req, x)); 190 | delegate = func(delegate); 191 | } 192 | // let pipe = [...HttpClient.intercepters, new HandlerIntercepter(handler, client)]; 193 | // let i = -1; 194 | // let chain = (request: IntercepterRequestContext) =>{ 195 | // i++; 196 | // let p = pipe[i].handle(request, chain); 197 | // return p; 198 | // } 199 | // return chain; 200 | return delegate; 201 | } 202 | } 203 | export const httpClient = new HttpClient(); 204 | //# sourceMappingURL=httpclient.js.map -------------------------------------------------------------------------------- /dist/url.js: -------------------------------------------------------------------------------- 1 | var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { 2 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); 3 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); 4 | return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); 5 | }; 6 | var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { 7 | if (kind === "m") throw new TypeError("Private method is not writable"); 8 | if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); 9 | if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); 10 | return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; 11 | }; 12 | var _Url_path; 13 | export class Url { 14 | constructor(url) { 15 | _Url_path.set(this, void 0); 16 | if (url == null) { 17 | return; 18 | } 19 | let pos = 0; 20 | if (url.indexOf('://') > 0) { 21 | pos = url.indexOf('://'); 22 | this.scheme = url.substr(0, pos); 23 | pos += 3; 24 | if (url.indexOf('/', pos + 1) >= 0) { 25 | this.host = url.substring(pos, url.indexOf('/', pos + 1)); 26 | pos = url.indexOf('/', pos + 1); 27 | } 28 | else { 29 | this.host = url.substring(pos); 30 | pos = url.length; 31 | } 32 | } 33 | this.pathAndQuery = url.substr(pos); 34 | } 35 | /** domain + port */ 36 | get host() { 37 | let h = this.domain; 38 | if (this.port != null && !isNaN(this.port)) { 39 | h = h + ':' + this.port; 40 | } 41 | return h !== null && h !== void 0 ? h : null; 42 | } 43 | set host(h) { 44 | if (h == null) { 45 | this.domain = null; 46 | this.port = null; 47 | return; 48 | } 49 | const c = countSymble(h, ':'); 50 | if (c === 1 || h.lastIndexOf(']') >= 0) { 51 | // [ipv4 or ipv6 or domain] + port 52 | const pos = h.lastIndexOf(':'); 53 | this.domain = h.substring(0, pos); 54 | this.port = parseInt(h.substring(pos + 1), 10); 55 | } 56 | else { 57 | // no port 58 | this.domain = h; 59 | this.port = null; 60 | } 61 | function countSymble(str, symble) { 62 | let pos = 0; 63 | let ct = 0; 64 | while (str.indexOf(symble, pos) >= 0) { 65 | pos = str.indexOf(symble, pos); 66 | pos += 1; 67 | ct += 1; 68 | } 69 | return ct; 70 | } 71 | } 72 | get pathAndQuery() { 73 | var _a, _b; 74 | if (this.path == null && this.queryString == null) { 75 | return null; 76 | } 77 | return `${(_a = this.path) !== null && _a !== void 0 ? _a : ''}${(_b = this.queryString) !== null && _b !== void 0 ? _b : ''}`; 78 | } 79 | set pathAndQuery(value) { 80 | this.parsePathAndQuery(value); 81 | } 82 | get path() { 83 | if (__classPrivateFieldGet(this, _Url_path, "f") == null || __classPrivateFieldGet(this, _Url_path, "f") === '') { 84 | return null; 85 | } 86 | if (!__classPrivateFieldGet(this, _Url_path, "f").startsWith('/')) { 87 | return `/${__classPrivateFieldGet(this, _Url_path, "f")}`; 88 | } 89 | return __classPrivateFieldGet(this, _Url_path, "f"); 90 | } 91 | set path(path) { 92 | if (path == null || path === '') { 93 | __classPrivateFieldSet(this, _Url_path, null, "f"); 94 | return; 95 | } 96 | if (!path.startsWith('/')) { 97 | path = '/' + path; 98 | } 99 | __classPrivateFieldSet(this, _Url_path, path, "f"); 100 | } 101 | get queryString() { 102 | if (this.query == null) { 103 | return null; 104 | } 105 | const list = []; 106 | for (const name in this.query) { 107 | if (typeof this.query[name] === 'function') { 108 | continue; 109 | } 110 | const kv = [encodeURIComponent(name), encodeURIComponent(this.query[name])].join('='); 111 | list.push(kv); 112 | } 113 | if (list.length === 0) { 114 | return null; 115 | } 116 | return `?${list.join('&')}`; 117 | } 118 | set queryString(v) { 119 | if (v == null) { 120 | return; 121 | } 122 | this.parseQuery(v); 123 | } 124 | get hasQuery() { 125 | if (this.query != null && Object.getOwnPropertyNames(this.query).length > 0) { 126 | return true; 127 | } 128 | return false; 129 | } 130 | get isAbsolute() { 131 | return this.scheme != null && this.scheme !== ''; 132 | } 133 | get isEmpty() { 134 | return this.scheme == null && this.host == null && this.pathAndQuery == null; 135 | } 136 | get isQuery() { 137 | return this.scheme == null && this.host == null && this.path == null && this.hasQuery; 138 | } 139 | toString() { 140 | var _a, _b; 141 | if (this.isAbsolute) { 142 | return `${this.scheme}://${this.host}${this.path == null && this.hasQuery ? '/' : ''}${(_a = this.pathAndQuery) !== null && _a !== void 0 ? _a : ''}`; 143 | } 144 | return (_b = this.pathAndQuery) !== null && _b !== void 0 ? _b : ''; 145 | } 146 | parsePathAndQuery(v) { 147 | if (v == null) { 148 | this.path = null; 149 | this.query = null; 150 | return; 151 | } 152 | const pos = v.indexOf('?'); 153 | if (pos >= 0) { 154 | this.path = v.substring(0, pos); 155 | this.queryString = v.substring(pos); 156 | } 157 | else { 158 | this.path = v; 159 | } 160 | } 161 | parseQuery(queryString) { 162 | if (queryString == null) { 163 | return; 164 | } 165 | if (queryString.startsWith('?')) { 166 | queryString = queryString.substr(1); 167 | } 168 | const kvpair = queryString.split('&'); 169 | if (kvpair.length > 0) { 170 | this.query = {}; 171 | for (const v of kvpair) { 172 | const pos = v.indexOf('='); 173 | if (pos < 0) { 174 | return; 175 | } 176 | this.query[decodeURIComponent(v.substr(0, pos))] = decodeURIComponent(v.substr(pos + 1)); 177 | } 178 | } 179 | else { 180 | this.query = null; 181 | } 182 | } 183 | /** return a new Url */ 184 | add(url) { 185 | var _a; 186 | if (url.isAbsolute) { 187 | return url.clone(); 188 | } 189 | if (this.hasQuery) { 190 | if (url.isQuery) { 191 | const u = this.clone(); 192 | (_a = u.query) !== null && _a !== void 0 ? _a : (u.query = {}); 193 | for (const name in url.query) { 194 | if (url.query.hasOwnProperty(name)) { 195 | u.query[name] = url.query[name]; 196 | } 197 | } 198 | return u; 199 | } 200 | else { 201 | return url.clone(); 202 | } 203 | } 204 | else { 205 | let thisUrl = this.toString(); 206 | let afterUrl = url.toString(); 207 | if (thisUrl.endsWith('/')) { 208 | thisUrl = thisUrl.substr(0, thisUrl.length - 1); 209 | } 210 | if (!afterUrl.startsWith('/')) { 211 | afterUrl = '/' + afterUrl; 212 | } 213 | return new Url(`${thisUrl}${afterUrl}`); 214 | } 215 | } 216 | clone() { 217 | return new Url(this.toString()); 218 | } 219 | } 220 | _Url_path = new WeakMap(); 221 | //# sourceMappingURL=url.js.map -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 适用于 uniapp 的 请求拦截库 HttpClient. 如果这个库帮助了您,请您在github上给个star, 或者dcloud 插件市场上点个赞。 2 | 3 | ## uni-httpclient 4 | 5 | [![npm version](https://badgen.net/npm/v/uni-httpclient)](https://www.npmjs.com/package/uni-httpclient) 6 | [![npm download](https://badgen.net/npm/dt/uni-httpclient)](https://www.npmjs.com/package/uni-httpclient) 7 | [![GitHub version](https://badgen.net/github/forks/john0king/uni-httpclient)](https://github.com/John0King/uni-HttpClient) 8 | [![GitHub star](https://badgen.net/github/stars/john0king/uni-httpclient)](https://github.com/John0King/uni-HttpClient) 9 | 10 | 11 | ## Update: 2025/8/18 12 | #### v1.5.1 13 | 14 | - 使用最新typescript sdk, 修复与vue3 中 类型导入问题 15 | 16 | ## Update: 2021/4/19 17 | #### v1.4.1 18 | 19 | - 变更: `HttpClient` 现在废弃全局拦截器了, 全部都是实例,原来的方法仍然兼容, 现在可以为不同的 api 创建不同的`HttpClient`实例了。 20 | - 变更: 现在支持 `httpclient.get({ url:'/api/do', ... })` 了,配置参数更加方便, 而且仍然兼容原来的接口 21 | - 新增: 我们支持原生微信了, 现在 `UniRequestHandler` 等,会在找不到 `uni` 对象的情况下使用 `wx` 对象。 22 | - 变更: `httpclient.intercepters` 实例的字段,类型从 `Array` 变更为 `IntercepterCollection extends Array` , 带来了 `insertBefore()` 和 `insertAfter()` 方法。 23 | - 变更: Demo 程序更新了, 带来了 拦截器的demo。 24 | 25 | ### url 操作 26 | 27 | ```ts 28 | // 拼接 29 | var urlstr = new Url('http://www.baidu.com').add(new Url('/?wd=uni-httpclient')).toString(); 30 | //检查 31 | var url = new Url(urlstr); 32 | console.log(url.scheme) // http 33 | console.log(url.domain) // www.baidu.com 34 | console.log(url.path) // / 35 | console.log(url.queryString) // ?wd=uni-httpclient 36 | console.log(url.pathAndQuery) // /?wd=uni-httpclient 37 | url.query['pn'] = 10 38 | console.log(url.toString()) // http://www.baidu.com/?wd=uni-httpclient&pn=10 39 | ``` 40 | 41 | ## 核心功能: 42 | - [x] 配置 `httpClient.setupDefaults()` (现在是实例方法了) 43 | - [x] query 44 | - [x] get 45 | - [x] post 46 | - [x] form (post with applicaton/www-urlencoded) 47 | - [x] delete 48 | - [x] put 49 | - [x] upload 50 | - [x] download 51 | - [x] 拦截/intercepter 52 | - [x] query 53 | - [x] upload 54 | - [x] download 55 | - [x] CancelToken 取消, 复刻在 .Net 中已经使用十几年的 `CancellationToken` 56 | - [x] ICancelSource 57 | - [x] ICancelToken 58 | - 拦截器 59 | - [x] JwtTokenIntercepter Json Web Token 拦截器 60 | - [x] AutoDomainIntercepter 自动添加域名的拦截器,用于将 `/api` 转化为 `http://localhost:8080/api` 61 | - [x] StatusCodeIntercepter 将statuscode 小于200 或 大于等于400 的请求视为错误,抛出 StatusCodeError 62 | - [x] TimeoutIntercepter 简单的实现 timeout, 该拦截器,注入或者链接一个现有的 `CancelToken` 来实现(重试时会重置) 63 | - [x] MaxTimeoutIntercepter 简单的实现 timeout, 该拦截器,注入或者链接一个现有的 `CancelToken` 来实现(重试时不会重置) 64 | - [x] RetryIntercepter 简单的实现 timeout, 该拦截器,注入或者链接一个现有的 `CancelToken` 来实现 65 | - [x] 数据模拟 66 | - [x] 自定义拦截器 67 | 68 | 69 | ## 使用方式 70 | 71 | ### 一、安装 72 | 1. 通过 npm/yarn 安装 73 | 74 | ```bash 75 | $> npm install uni-httpclient 76 | ``` 77 | 2. 或者通过Hbuild 导入或者从插件市场下载手动安装 78 | 79 | ### 二、配置 80 | 81 | ```ts 82 | //===========新功能=========== 83 | // 注意类型 HttpClient 和 实例 httpClient 84 | import { HttpClient} from "uni-httpclient"; // 名字具体看你把该库放在哪 85 | 86 | // setupDefaults 是 HttpClient 这个类的静态函数 87 | // 你必须配置以下内容才能将所有的拦截器都打开,如果不配置 其中某个比如 retryCount, 则重试拦截器将不会添加 88 | HttpClient.setupDefaults({ 89 | timeout:10, 90 | maxTimeout:15, 91 | retryCount:1, // 建议重试1次就好 92 | retryDelay:1000, //1秒,默认值 93 | statusCodeError:true, 94 | baseUrl:"http://localhost:500/api/" 95 | }) 96 | 97 | //=======自定义方式============= 98 | 99 | //1. 配置 在 main.ts 中配置 100 | import { HttpClient} from "uni-httpclient"; // 名字具体看你把该库放在哪 101 | const domainIntercepter = new AutoDomainIntercepter((url)=>{ 102 | //url 为请求url, 可以根据url添加自己逻辑, 103 | //比如 /api 映射到 api.com, /v2 映射到 v2.api.com 104 | 105 | return "http://localhost:8080" 106 | }) 107 | const jwtTokenIntercepter = new JwtTokenIntercepter((url)=>{ 108 | // 因为拦截器会按顺序执行,所以此处的url已经是完整的url, 109 | // 在这里可以 url 参数 给不同的域名/路径追加不同的token 110 | let domain = "*" 111 | if (url.startWith("http://a.example.com"){ 112 | domain = "a" 113 | } 114 | else if ( url.startWith("http://b.example.com")){ 115 | domain = "b"; 116 | } 117 | // tokenStorage 是一个自己实现的类,用来管理token 118 | return tokenStorage.getToken(domain); 119 | }) 120 | httpClient.intercepters.push(new TimeoutIntercepter( 20 )); // 添加 使用 timeout 参数的必备拦截器, 可以不填,填上则未全局超时, 121 | //记得在 下载和上传 api上 利用 preventTimeout:true 来阻止该拦截器发生作用,(上传和下载是相对比较耗时的操作) 122 | HttpClient.intercepters.push(domainIntercepter) 123 | HttpClient.intercepters.push(jwtTokenIntercepter) 124 | 125 | ``` 126 | 127 | ### 三、使用 128 | ```ts 129 | import { httpClient } from "uni-httpclient"; 130 | // 如果不喜欢 httpClient 这个词, 可以用 as 重命名 131 | // import { httpClient as http} from "uni-httpclient"; 132 | httpClient.get(`/api/user/info`) 133 | .then(r=>{ 134 | // 处理返回的数据 135 | }) 136 | ``` 137 | 138 | ## 取消 / CancelToken 的使用 139 | 除了使用 timeout , 你可以手动使用 `CancelToken`, 140 | 手动使用 `CancelToken` 无需添加 `TimeoutIntercepter`,添加上也不受影响, 当同时使用时, 两者都会发生作用(但只会发生一次)。 141 | 142 | ```typescript 143 | import {CancelToken } from "我们的库地址"; 144 | let cancelToken = new CancelToken(); 145 | httpClient.Post("/api/do",null,null,null,{ cancelToken: cancelToken }) 146 | .then(x=> { }); 147 | 148 | // 需要取消的时候 149 | 150 | cancelToken.cancel(); 151 | 152 | ``` 153 | 154 | ### 详细解释 `CancelToken` (需要了解部分typescript 知识) 155 | 156 | `CanelToken` 实现了 `ICancelSource` 和 `ICancelToken`(这两个接口在 js中是不存在的,要了解这个必须了解 typescript interface 是什么,简单的说就是单纯的token 不能调用取消,只有 source 可以调用取消), 之所以说这个,是希望大家更具体的知道如何替换`CancelToken`, 157 | 比如有一个 `CancelToken` 叫做 `a`是传入的 , 还有一个 `b` 我们自己创建的, 当他们在一起时该怎么处理,首先我们**不应该直接操作`a`**, 因为`a`有自己的事件,而且可能传给了多个function, 正确的做法是 当 `a` 取消时,我们的`b`也取消,如果`a` 没有取消,我们就操作我们的取消 158 | ```typescript 159 | // 入口 160 | function main(){ 161 | let cancel = new CancelToken(); 162 | cancel.CancelAfter(10 * 1000);//10 秒 163 | cancel.register(x=> console.log(`token a cancel 了`)) 164 | doLongStuff(cancel) 165 | .then(()=>console.log(`没有取消`)) 166 | .cache(e=> console.log(`最终还是取消了`)) 167 | } 168 | 169 | function doLongStuff(cancelToken:ICancelToken):Promise{ 170 | // 我们里面要求 5秒就取消 171 | let runningTime = (Math.random() * 20); //随机0-20秒 172 | let cancel = new Cancel(); 173 | setTimeout(()=> cancel.cancel(), 5000); 174 | cancel.linkeToken(cancelToken); 175 | //这里里面的 cancel 跟外面的没有关系, 里面的取消,并不会导致外面的 取消,但外面的 token取消,会触发里面的取消 176 | 177 | 178 | return new Promise((resolve,reject)=>{ 179 | setTimeout(()=>{ 180 | // 检查自己的token,不要管别的 181 | if(cancel.isCanceled){ 182 | reject(`canceled`) 183 | } 184 | else{ 185 | resove(); 186 | } 187 | }, runningTime * 1000) 188 | 189 | }) 190 | } 191 | ``` 192 | 193 | ## 错误 194 | 195 | 我们的拦截器产生的错误,都是我们自己定义的类型, 可以使用 instanceof 来测试是否是特定的错误 如 196 | ```typescript 197 | httpClient.Get("/api/get") 198 | .cache(e=>{ 199 | if(e instanceof StatusCodeError){ 200 | .... 201 | } 202 | else if (e instanceof CancelError){ 203 | ... 204 | } 205 | }) 206 | ``` 207 | 208 | StatusCodeIntercepter 产生的错误是 StatusCodeError, 209 | Cancel 产生的错误是 CancelError 210 | 211 | 212 | ## 拦截器 和 模拟数据源 213 | 214 | 模拟数据源要使用自定义的拦截器,且应该将此拦截器放在第一个拦截器(不要让AutoDomainIntercepter发挥作用), 215 | 不懂Typescript 的同学可以将一下代码放到 https://www.staging-typescript.org/zh/play 来查看js版本 216 | ```typescript 217 | import { 218 | HttpClientIntercepter, 219 | IntercepterRequestContext, 220 | IntercepterResponseContext, 221 | IntercepterDelegate, 222 | TaskSource, 223 | Task 224 | } from "uni-httpclient"; 225 | export class MyDataIntercepter implements HttpClientIntercepter { 226 | constructor() { } 227 | 228 | async handle(request: IntercepterRequestContext, next: IntercepterDelegate): Promise { 229 | await Task.delay(2000); // 延时2秒 230 | 231 | if(request.url == "/api/api1"){ 232 | return { 233 | httpClient: null , 234 | httpClientHander: null, 235 | statusCode: 200, 236 | data: { /*您的数据*/ }, 237 | header: {}, 238 | pipeOptions:request.pipeOptions 239 | } 240 | } 241 | // 只要你不调用 next , 就不会往下执行,你随时可以阻止往下执行 242 | return await next(request); 243 | } 244 | } 245 | 246 | // 使用 247 | 248 | httpClient.setupDefaults({ 249 | retryCount: 1, 250 | timeout:15, 251 | statusCodeError:true, 252 | baseUrl:"https://localhost:5001" 253 | }); 254 | HttpClient.intercepters.unshift(new MyDataIntercepter()) // 使用unshif 将此拦截器放在最开始的时候 255 | 256 | ``` 257 | 258 | ## 拦截器原理 259 | 260 | ``` 261 | 请求 ---> 拦截器A -----> 拦截器B ----> .... ----> IHttpClientHander 262 | | 263 | 处理请求(底层请求方法) 264 | | 265 | 响应 <---- 拦截器A <----- 拦截器B <---- .... <--- IHttpClientHander 266 | 267 | ``` 268 | 269 | Powered by [金昇网络](https://www.kingasc.com) 270 | 如果这个库帮助到了您, 请再 github https://github.com/john0king/uni-httpclient 给个star 271 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/helper-string-parser@^7.27.1": 6 | version "7.27.1" 7 | resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" 8 | integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== 9 | 10 | "@babel/helper-validator-identifier@^7.27.1": 11 | version "7.27.1" 12 | resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" 13 | integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== 14 | 15 | "@babel/parser@^7.28.0": 16 | version "7.28.3" 17 | resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.28.3.tgz#d2d25b814621bca5fe9d172bc93792547e7a2a71" 18 | integrity sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA== 19 | dependencies: 20 | "@babel/types" "^7.28.2" 21 | 22 | "@babel/types@^7.28.2": 23 | version "7.28.2" 24 | resolved "https://registry.npmmirror.com/@babel/types/-/types-7.28.2.tgz#da9db0856a9a88e0a13b019881d7513588cf712b" 25 | integrity sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ== 26 | dependencies: 27 | "@babel/helper-string-parser" "^7.27.1" 28 | "@babel/helper-validator-identifier" "^7.27.1" 29 | 30 | "@dcloudio/types@3.4.19": 31 | version "3.4.19" 32 | resolved "https://registry.npmmirror.com/@dcloudio/types/-/types-3.4.19.tgz#cf4b23cac1df4ba1ad7871a2a0658b57435f2ba3" 33 | integrity sha512-1foayOFEAQ+jnQLt3ACsovCNjer3/fXn1I2VBpmDOzs2nk/n4UHwRLAxZV/RpxRqaGOPEvKrO/Pq+VI6sAmuRw== 34 | 35 | "@jridgewell/sourcemap-codec@^1.5.0": 36 | version "1.5.5" 37 | resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" 38 | integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== 39 | 40 | "@vue/compiler-core@3.5.18": 41 | version "3.5.18" 42 | resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.18.tgz#521a138cdd970d9bfd27e42168d12f77a04b2074" 43 | integrity sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw== 44 | dependencies: 45 | "@babel/parser" "^7.28.0" 46 | "@vue/shared" "3.5.18" 47 | entities "^4.5.0" 48 | estree-walker "^2.0.2" 49 | source-map-js "^1.2.1" 50 | 51 | "@vue/compiler-dom@3.5.18": 52 | version "3.5.18" 53 | resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz#e13504492c3061ec5bbe6a2e789f15261d4f03a7" 54 | integrity sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A== 55 | dependencies: 56 | "@vue/compiler-core" "3.5.18" 57 | "@vue/shared" "3.5.18" 58 | 59 | "@vue/compiler-sfc@3.5.18": 60 | version "3.5.18" 61 | resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz#ba1e849561337d809937994cdaf900539542eeca" 62 | integrity sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA== 63 | dependencies: 64 | "@babel/parser" "^7.28.0" 65 | "@vue/compiler-core" "3.5.18" 66 | "@vue/compiler-dom" "3.5.18" 67 | "@vue/compiler-ssr" "3.5.18" 68 | "@vue/shared" "3.5.18" 69 | estree-walker "^2.0.2" 70 | magic-string "^0.30.17" 71 | postcss "^8.5.6" 72 | source-map-js "^1.2.1" 73 | 74 | "@vue/compiler-ssr@3.5.18": 75 | version "3.5.18" 76 | resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz#aecde0b0bff268a9c9014ba66799307c4a784328" 77 | integrity sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g== 78 | dependencies: 79 | "@vue/compiler-dom" "3.5.18" 80 | "@vue/shared" "3.5.18" 81 | 82 | "@vue/reactivity@3.5.18": 83 | version "3.5.18" 84 | resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.18.tgz#fe32166e3938832c54b4134e60e9b58ca7d9bdb4" 85 | integrity sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg== 86 | dependencies: 87 | "@vue/shared" "3.5.18" 88 | 89 | "@vue/runtime-core@3.5.18": 90 | version "3.5.18" 91 | resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.18.tgz#9e9ae8b9491548b53d0cea2bf25746d27c52e191" 92 | integrity sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w== 93 | dependencies: 94 | "@vue/reactivity" "3.5.18" 95 | "@vue/shared" "3.5.18" 96 | 97 | "@vue/runtime-dom@3.5.18": 98 | version "3.5.18" 99 | resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz#1150952d1048b5822e4f1dd8aed24665cbb22107" 100 | integrity sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw== 101 | dependencies: 102 | "@vue/reactivity" "3.5.18" 103 | "@vue/runtime-core" "3.5.18" 104 | "@vue/shared" "3.5.18" 105 | csstype "^3.1.3" 106 | 107 | "@vue/server-renderer@3.5.18": 108 | version "3.5.18" 109 | resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.18.tgz#e9fa267b95b3a1d8cddca762377e5de2ae9122bd" 110 | integrity sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA== 111 | dependencies: 112 | "@vue/compiler-ssr" "3.5.18" 113 | "@vue/shared" "3.5.18" 114 | 115 | "@vue/shared@3.5.18": 116 | version "3.5.18" 117 | resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.18.tgz#529f24a88d3ed678d50fd5c07455841fbe8ac95e" 118 | integrity sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA== 119 | 120 | csstype@^3.1.3: 121 | version "3.1.3" 122 | resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" 123 | integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== 124 | 125 | entities@^4.5.0: 126 | version "4.5.0" 127 | resolved "https://registry.npmmirror.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" 128 | integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== 129 | 130 | estree-walker@^2.0.2: 131 | version "2.0.2" 132 | resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 133 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 134 | 135 | magic-string@^0.30.17: 136 | version "0.30.17" 137 | resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" 138 | integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== 139 | dependencies: 140 | "@jridgewell/sourcemap-codec" "^1.5.0" 141 | 142 | nanoid@^3.3.11: 143 | version "3.3.11" 144 | resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" 145 | integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== 146 | 147 | picocolors@^1.1.1: 148 | version "1.1.1" 149 | resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" 150 | integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== 151 | 152 | postcss@^8.5.6: 153 | version "8.5.6" 154 | resolved "https://registry.npmmirror.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" 155 | integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== 156 | dependencies: 157 | nanoid "^3.3.11" 158 | picocolors "^1.1.1" 159 | source-map-js "^1.2.1" 160 | 161 | source-map-js@^1.2.1: 162 | version "1.2.1" 163 | resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" 164 | integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== 165 | 166 | typescript@^5.9.2: 167 | version "5.9.2" 168 | resolved "https://registry.npmmirror.com/typescript/-/typescript-5.9.2.tgz#d93450cddec5154a2d5cabe3b8102b83316fb2a6" 169 | integrity sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A== 170 | 171 | vue@^3.5.18: 172 | version "3.5.18" 173 | resolved "https://registry.npmmirror.com/vue/-/vue-3.5.18.tgz#3d622425ad1391a2b0138323211ec784f4415686" 174 | integrity sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA== 175 | dependencies: 176 | "@vue/compiler-dom" "3.5.18" 177 | "@vue/compiler-sfc" "3.5.18" 178 | "@vue/runtime-dom" "3.5.18" 179 | "@vue/server-renderer" "3.5.18" 180 | "@vue/shared" "3.5.18" 181 | --------------------------------------------------------------------------------