@allkit/http-client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,82 @@
1
+ import axios from 'axios'
2
+ import { createWXAdapter } from '../adapter/taro'
3
+ import { defaultConfig } from './config'
4
+ import { handleInterceptor } from './interceptor'
5
+ import { parseRequest } from './request'
6
+ import type { HttpClient, HttpRequestConfig, HttpRequestConfigWrap } from '../types'
7
+
8
+ class Http {
9
+ private static _instance: Http | null = null
10
+ private _client: HttpClient | null = null
11
+ defaultReqConfig: HttpRequestConfig
12
+
13
+ constructor(reqConfig: HttpRequestConfig) {
14
+ this.defaultReqConfig = reqConfig
15
+ this.createHttp()
16
+ }
17
+
18
+ public static get instance(): Http {
19
+ return Http._instance!
20
+ }
21
+
22
+ /** 初始化配置 */
23
+ public static init(config?: HttpRequestConfigWrap) {
24
+ if (!Http._instance) {
25
+ const _config = Object.assign({}, defaultConfig, config)
26
+ Http._instance = new Http(_config)
27
+ }
28
+ return Http._instance
29
+ }
30
+
31
+ public createHttp() {
32
+ const _request = axios.create(defaultConfig)
33
+ handleInterceptor(_request, this.defaultReqConfig)
34
+ this._client = _request
35
+ }
36
+
37
+ /** 设置baseUrl */
38
+ setBaseURL(baseURL: string) {
39
+ this.defaultReqConfig.baseURL = baseURL
40
+ }
41
+
42
+ setAdapter(option: Record<string, any>) {
43
+ //@ts-ignore
44
+ const _wx = typeof wx === 'object' ? wx : ''
45
+ if (_wx) {
46
+ option.adapter = createWXAdapter
47
+ }
48
+ }
49
+
50
+ public get client(): HttpClient {
51
+ return this._client!
52
+ }
53
+ /** 通用请求 */
54
+ request<T = any>(reqConfig: HttpRequestConfigWrap) {
55
+ const config = Object.assign({}, this.defaultReqConfig, reqConfig)
56
+ const option = parseRequest(config) as Record<string, any>
57
+ this.setAdapter(option)
58
+ return this.client.request<any, T>(option)
59
+ }
60
+
61
+ /** get请求 */
62
+ public static get<T = any>(reqConfig: HttpRequestConfigWrap) {
63
+ return Http.init().request<T>({ method: 'get', ...reqConfig })
64
+ }
65
+
66
+ /** post请求 */
67
+ public static post<T = any>(reqConfig: HttpRequestConfigWrap) {
68
+ return Http.init().request<T>({ method: 'post', ...reqConfig })
69
+ }
70
+
71
+ /** put 请求 */
72
+ public static put<T = any>(reqConfig: HttpRequestConfigWrap) {
73
+ return Http.init().request<T>({ method: 'put', ...reqConfig })
74
+ }
75
+
76
+ /** delete 请求 */
77
+ public static delete<T = any>(reqConfig: HttpRequestConfigWrap) {
78
+ return Http.init().request<T>({ method: 'delete', ...reqConfig })
79
+ }
80
+ }
81
+
82
+ export default Http
@@ -0,0 +1,51 @@
1
+ import { EnumContentType, EnumMethod } from '../constants'
2
+ import { commonResponseErrorMsg } from './interceptor'
3
+ import type { HttpRequestConfig, HttpResponse } from '../types'
4
+
5
+ export const defaultInterceptors = () => {
6
+ return {
7
+ response: (res: HttpResponse) => {
8
+ return new Promise((resolve, reject) => {
9
+ const { showErrorMsg, ignoreToast } = res.config
10
+ if (res.status === 200) {
11
+ if (res.data.code === 0) {
12
+ return resolve(res.data.data)
13
+ }
14
+ //code!==0
15
+ //忽略错误,或者在忽略列表中,就不显示错误信息
16
+ if (
17
+ (Array.isArray(ignoreToast) && !ignoreToast.includes(res.data.code)) ||
18
+ !ignoreToast
19
+ ) {
20
+ showErrorMsg?.(res.data.msg || res.message || '接口错误')
21
+ }
22
+ return reject(res)
23
+ }
24
+ const errorTips = commonResponseErrorMsg(res)
25
+ showErrorMsg?.(errorTips)
26
+ return reject(res)
27
+ })
28
+ },
29
+ rejectResponse: (res: any) => {
30
+ const { showErrorMsg, ignoreToast } = res.config
31
+ if ((Array.isArray(ignoreToast) && !ignoreToast.includes(res.data.code)) || !ignoreToast) {
32
+ const msg = res.response?.data?.message || res.message || '接口错误'
33
+ showErrorMsg?.(msg)
34
+ }
35
+ return Promise.reject(res.response)
36
+ },
37
+ }
38
+ }
39
+
40
+ /** 默认的配置 */
41
+ export const defaultConfig: HttpRequestConfig = {
42
+ baseURL: '',
43
+ headers: {
44
+ method: EnumMethod.POST,
45
+ 'Content-Type': EnumContentType.JSON,
46
+ },
47
+ timeout: 10000,
48
+ loading: false,
49
+ method: 'POST',
50
+ interceptors: defaultInterceptors(),
51
+ }
@@ -0,0 +1,6 @@
1
+ import Http from './Http'
2
+ import { defaultConfig, defaultInterceptors } from './config'
3
+
4
+ export { defaultConfig, defaultInterceptors }
5
+
6
+ export default Http
@@ -0,0 +1,98 @@
1
+ import { isEmptyObject } from '../utils'
2
+ import type { AxiosInstance } from 'axios'
3
+ import type { HttpInterceptor, HttpRequestConfig, HttpResponse, MultiInterceptor } from '../types'
4
+
5
+ export function mergeInterceptor(httpInterceptor?: Partial<HttpInterceptor>) {
6
+ const opt: MultiInterceptor = {
7
+ request: [],
8
+ response: [],
9
+ rejectRequest: [],
10
+ rejectResponse: []
11
+ }
12
+
13
+ // 重试
14
+ if (httpInterceptor && !isEmptyObject(httpInterceptor)) {
15
+ for (const keyName in opt) {
16
+ const optInterceptor = opt[keyName as keyof typeof opt]
17
+ const interceptor = httpInterceptor[keyName as keyof typeof httpInterceptor] || []
18
+ // @ts-ignore
19
+ opt[keyName] = optInterceptor.concat(interceptor)
20
+ }
21
+ }
22
+
23
+ const interceptorList = [
24
+ ...opt.request.map((i) => {
25
+ return {
26
+ callback: i,
27
+ type: 'request'
28
+ }
29
+ }),
30
+ ...opt.response.map((i) => {
31
+ return {
32
+ callback: i,
33
+ type: 'response'
34
+ }
35
+ }),
36
+ ...opt.rejectRequest.map((i) => {
37
+ return {
38
+ callback: i,
39
+ type: 'rejectRequest'
40
+ }
41
+ }),
42
+ ...opt.rejectResponse.map((i) => {
43
+ return {
44
+ callback: i,
45
+ type: 'rejectResponse'
46
+ }
47
+ })
48
+ ].filter(Boolean)
49
+ return interceptorList
50
+ }
51
+
52
+ /**
53
+ * 处理拦截器
54
+ */
55
+ export function handleInterceptor(request: AxiosInstance, reqConfig: HttpRequestConfig) {
56
+ // 拦截器配置
57
+ const interceptorList = mergeInterceptor(reqConfig.interceptors)
58
+ interceptorList.forEach((interceptor) => {
59
+ const { type, callback } = interceptor
60
+ type === 'request' && request.interceptors?.request?.use(callback as any)
61
+ type === 'response' && request.interceptors?.response?.use(callback as any)
62
+ type === 'rejectRequest' && request.interceptors?.request?.use(undefined, callback)
63
+ type === 'rejectResponse' && request.interceptors?.response?.use(undefined, callback)
64
+ })
65
+ }
66
+
67
+ export function commonResponseErrorMsg(res: HttpResponse) {
68
+ const msg = res.data?.message || res.msg
69
+ let errorMsg = ''
70
+ switch (res.status) {
71
+ case 401:
72
+ errorMsg = '401:' + msg
73
+ break
74
+ case 403:
75
+ errorMsg = msg
76
+ break
77
+ case 404:
78
+ errorMsg = '404: ' + msg
79
+ break
80
+ case 422:
81
+ errorMsg = '请求参数错误' + msg
82
+ break
83
+ case 426:
84
+ errorMsg = '426: ' + msg
85
+ break
86
+ case 428:
87
+ errorMsg = '428: ' + msg
88
+ break
89
+ case 500: {
90
+ errorMsg = '服务器错误: ' + msg
91
+ break
92
+ }
93
+ default:
94
+ errorMsg = '未知的情况'
95
+ break
96
+ }
97
+ return errorMsg
98
+ }
@@ -0,0 +1,75 @@
1
+ import md5 from 'js-md5'
2
+ import { EnumContentType } from '../constants'
3
+ import { isFunction } from '../utils'
4
+ import type { HttpRequestConfig } from '../types'
5
+
6
+ /**
7
+ * 创建请求头
8
+ */
9
+ export function parseHeaders(config: HttpRequestConfig) {
10
+ const { url, data } = config
11
+
12
+ const token = isFunction(config.token) ? config.token() || '' : config.token || ''
13
+
14
+ const _getSign = () => {
15
+ return md5(md5(token).toUpperCase() + JSON.stringify(data || {})).toUpperCase()
16
+ }
17
+ const _headers = {
18
+ ...config.headers,
19
+ method: url,
20
+ sign: _getSign()
21
+ } as Record<string, any>
22
+ if (token) {
23
+ _headers.Authorization = 'Bearer ' + token
24
+ }
25
+ return _headers
26
+ }
27
+
28
+ /**
29
+ * 创建请求体
30
+ */
31
+ export function parseBody(config: HttpRequestConfig) {
32
+ const { data = {} } = config
33
+ const contentType = config.headers?.['Content-Type'] || config.headers?.['content-type']
34
+ const option = { data: {} }
35
+ switch (contentType) {
36
+ case EnumContentType.URL_ENCODED: {
37
+ const params = new window.URLSearchParams()
38
+ for (const [key, val] of Object.entries(data)) {
39
+ params.append(key, val as string)
40
+ }
41
+ option['data'] = params
42
+ //data = qs.stringify(param, { arrayFormat: 'brackets' })
43
+ break
44
+ }
45
+ case EnumContentType.FORM: {
46
+ const formData = new FormData()
47
+ for (const [key, val] of Object.entries(data)) {
48
+ formData.append(key, val as string)
49
+ }
50
+ option['data'] = formData
51
+ break
52
+ }
53
+ default:
54
+ option['data'] = data
55
+ break
56
+ }
57
+ return option
58
+ }
59
+
60
+ /**
61
+ * 处理转换请求
62
+ */
63
+ export function parseRequest(config: HttpRequestConfig) {
64
+ //处理请求体
65
+ const body = parseBody(config)
66
+ //处理请求头
67
+ const headers = parseHeaders(config)
68
+ //处理请求行
69
+ //const url = parseUrl(config.url!)
70
+ return {
71
+ ...config,
72
+ headers,
73
+ ...body
74
+ }
75
+ }
package/src/index.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { EnumMethod } from './constants'
2
+ import Http from './core'
3
+ import type { HttpRequestConfigWrap } from './types'
4
+
5
+ export * from './core'
6
+ export * from './types'
7
+
8
+ /**
9
+ * 发送请求
10
+ * 默认post
11
+ */
12
+ export const useHttp = <T = any>(config: HttpRequestConfigWrap) => {
13
+ config.method = config.method || EnumMethod.POST
14
+ return Http.init().request<T>(config)
15
+ }
16
+
17
+ export { Http }
18
+ export default Http
package/src/types.ts ADDED
@@ -0,0 +1,82 @@
1
+ import type { AxiosInstance, AxiosRequestConfig } from 'axios'
2
+ import type { EnumContentType, EnumMethod } from './constants'
3
+
4
+ export type MethodValueType = (typeof EnumMethod)[keyof typeof EnumMethod] | string
5
+
6
+ export interface HttpRequestConfig<T = any> extends AxiosRequestConfig<T> {
7
+ /**
8
+ * token,可以是个函数
9
+ */
10
+ token?: string | (() => string)
11
+
12
+ /** userId ,可以是函数 */
13
+ userId?: string | (() => string)
14
+
15
+ // 是否开启loading
16
+ loading?: boolean
17
+ /**
18
+ * loading配置
19
+ */
20
+ loadingOption?: {
21
+ show: () => void
22
+ hide: () => void
23
+ }
24
+
25
+ /**
26
+ * 是否忽略错误提示
27
+ */
28
+ ignoreToast?: boolean | Array<number | string>
29
+
30
+ /**
31
+ * 错误提示
32
+ * @param msg - 后台返回错误信息
33
+ */
34
+ showErrorMsg?: (msg: string) => void
35
+ casToken?: boolean
36
+ headers: {
37
+ method: MethodValueType
38
+ 'Content-Type': EnumContentType
39
+ 'content-type'?: EnumContentType
40
+ 'X-menu-id'?: string
41
+ 'x-from'?: number | string
42
+ 'X-associated-system-code'?: string
43
+ [key: string]: string | number | undefined
44
+ }
45
+ interceptors?: Partial<HttpInterceptor>
46
+ }
47
+
48
+ export type HttpRequestConfigWrap<T = any> = Omit<HttpRequestConfig<T>, 'headers'> & {
49
+ headers?: Partial<HttpRequestConfig['headers']>
50
+ }
51
+
52
+ export interface HttpResponse<T = any> {
53
+ data: T
54
+ code: number
55
+ msg: string
56
+ success: boolean
57
+ headers: HttpRequestConfig['headers']
58
+ config: HttpRequestConfigWrap<T>
59
+ [key: string]: any
60
+ }
61
+
62
+ export interface HttpClient extends AxiosInstance {
63
+ create?: (config: HttpRequestConfig) => any
64
+ }
65
+
66
+ export type HttpInterceptorRequest = (value: AxiosRequestConfig) => Record<string, any>
67
+ export type HttpInterceptorResponse = (value: HttpResponse) => Promise<any> | HttpResponse
68
+ export type HttpInterceptorReject = (error: any) => any
69
+
70
+ export interface HttpInterceptor {
71
+ request: HttpInterceptorRequest | Array<HttpInterceptorRequest>
72
+ response: HttpInterceptorResponse | Array<HttpInterceptorResponse>
73
+ rejectRequest: HttpInterceptorReject | Array<HttpInterceptorReject>
74
+ rejectResponse: HttpInterceptorReject | Array<HttpInterceptorReject>
75
+ }
76
+
77
+ export interface MultiInterceptor {
78
+ request: Array<HttpInterceptorRequest>
79
+ rejectRequest: Array<HttpInterceptorReject>
80
+ rejectResponse: Array<HttpInterceptorReject>
81
+ response: Array<HttpInterceptorResponse>
82
+ }
@@ -0,0 +1,36 @@
1
+ const toString = Object.prototype.toString
2
+
3
+ export function is(val: unknown, type: string) {
4
+ return toString.call(val) === `[object ${type}]`
5
+ }
6
+
7
+ export function isObject(val: any): val is Record<any, any> {
8
+ return val !== null && is(val, 'Object')
9
+ }
10
+
11
+ export function isFunction(val: unknown): val is Function {
12
+ return typeof val === 'function'
13
+ }
14
+
15
+ /**
16
+ * 检测当前类型是否是空对象
17
+ * @param obj - 检测当前类型
18
+ * @returns 如果为空的对象则返回true、否则返回false
19
+ */
20
+ export const isEmptyObject = (obj: any): boolean => {
21
+ return isObject(obj) && Object.keys(obj as Object).length === 0
22
+ }
23
+
24
+ /**
25
+ * 随机数
26
+ * @param count - 位数
27
+ */
28
+ export const random = (count: number) => {
29
+ const num = Date.now() + Math.floor(1000 * Math.random() + 1000)
30
+ if (count) {
31
+ return num.toString().substr(-count)
32
+ }
33
+ return num.toString()
34
+ }
35
+
36
+ export const isKuaShengClient = navigator.userAgent.toLowerCase().indexOf('kuasheng-2.0') >= 0
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "extends": "@allkit/tsconfig/tsconfig.web.json",
3
+ "compilerOptions": {
4
+ "allowSyntheticDefaultImports": true,
5
+ "types": [
6
+ "vite/client"
7
+ ],
8
+ "baseUrl": ".",
9
+ "paths": {
10
+ "@/*": [
11
+ "src/*"
12
+ ],
13
+ "~/*": [
14
+ "src/*"
15
+ ]
16
+ }
17
+ },
18
+ "include": [
19
+ "src/",
20
+ "src/**/*.ts",
21
+ "src/**/*.d.ts",
22
+ "src/**/*.tsx",
23
+ "src/**/*.vue",
24
+ "types/*.d.ts"
25
+ ]
26
+ }
@@ -0,0 +1,16 @@
1
+ export {}
2
+
3
+ declare global {
4
+ interface IWxRequest {
5
+ url: string
6
+ data: Record<string, any>
7
+ header?: Record<string, string | number | undefined>
8
+ success: (res: Record<string, any>) => void
9
+ fail: (error: any) => void
10
+ complete: () => void
11
+ [key: string]: any
12
+ }
13
+ interface Wx {
14
+ request: (req: IWxRequest) => void
15
+ }
16
+ }