shinnosuke
4 天以前 2c01718e732f7c4842bc4711484bbd59345caf49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import { getAccessToken, clearSession } from './session.uts'
import { getApiBaseUrl, isApiConfigured } from '../config/api.uts'
 
export type HttpError = {
    code: string
    message: string
    statusCode: number
    traceId: string
}
 
export type HttpRequestOptions = {
    path: string
    method?: string
    data?: any
    idempotencyKey?: string
    skipAuth?: boolean
}
 
const requestTimeout = 15000
 
const createRequestId = (): string => 'tc-' + Date.now() + '-' + Math.floor(Math.random() * 1000000)
const buildUrl = (path: string): string => {
    const baseUrl = getApiBaseUrl()
    if (path.indexOf('http://') == 0 || path.indexOf('https://') == 0) return path
    return baseUrl.replace(/\/$/, '') + '/' + path.replace(/^\//, '')
}
 
export const resolveApiUrl = (path: string): string => {
    if (path.indexOf('/uploads/') == 0 || path.indexOf('/api/') == 0) return buildUrl(path)
    return path
}
const unavailable = (): HttpError => ({ code: 'API_NOT_CONFIGURED', message: '后台服务尚未配置', statusCode: 0, traceId: '' })
 
export const request = <T>(options: HttpRequestOptions, onSuccess: (data: T, traceId: string) => void, onError: (error: HttpError) => void): (() => void) => {
    if (!isApiConfigured() || options.path.length == 0) {
        onError(unavailable())
        return () => {}
    }
    const headers: any = {
        'Content-Type': 'application/json',
        'X-Request-Id': createRequestId()
    }
    if (!options.skipAuth) {
        const token = getAccessToken()
        if (token.length > 0) headers['Authorization'] = 'Bearer ' + token
    }
    if (options.idempotencyKey != null && options.idempotencyKey.length > 0) headers['X-Idempotency-Key'] = options.idempotencyKey
    const task: any = uni.request({
        url: buildUrl(options.path),
        method: options.method != null ? options.method : 'GET',
        data: options.data,
        header: headers,
        timeout: requestTimeout,
        success: (response: any) => {
            const payload: any = response.data
            const traceId = payload != null && payload.traceId != null ? payload.traceId as string : ''
            const businessCode = payload != null && payload.code != null ? payload.code : 0
            if (response.statusCode == 401) {
                clearSession()
                onError({ code: 'UNAUTHORIZED', message: '登录已失效,请重新登录', statusCode: 401, traceId: traceId })
                return
            }
            if (response.statusCode < 200 || response.statusCode >= 300) {
                onError({ code: 'HTTP_' + response.statusCode, message: payload != null && payload.message != null ? payload.message as string : '服务暂不可用', statusCode: response.statusCode, traceId: traceId })
                return
            }
            if (businessCode != 0 && businessCode != 200) {
                onError({ code: '' + businessCode, message: payload != null && payload.message != null ? payload.message as string : '业务处理失败', statusCode: response.statusCode, traceId: traceId })
                return
            }
            onSuccess((payload != null && payload.data != null ? payload.data : payload) as T, traceId)
        },
        fail: (error: any) => onError({ code: 'NETWORK_ERROR', message: error != null && error.errMsg != null ? error.errMsg as string : '网络连接失败,请稍后重试', statusCode: 0, traceId: '' })
    })
    return () => task.abort()
}