333
schangxiang@126.com
2025-09-19 18966e02fb573c7e2bb0c6426ed792b38b910940
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
'use strict';
/**
 * Copyright (c) 2017 Baidu.com, Inc. All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @file baseClient
 * @author baiduAip
 */
const DevAuth = require('../auth/devAuth');
 
const DevAuthToken = require('../auth/devAuthToken');
 
 
/**
 * 无授权判断状态
 *
 * @const
 * @type {number}
 */
const AUTHTYPE_INIT = 0;
 
/**
 * 确定为云用户
 *
 * @const
 * @type {number}
 */
const AUTHTYPE_BCE = 1;
 
/**
 * 确定为开发者用户(手动输入token模式,以及token中包含了正确的scope)
 *
 * @const
 * @type {number}
 */
const AUTHTYPE_DEV = 2;
 
/**
 * 获取开发者token成功用户
 *
 * @const
 * @type {number}
 */
const AUTHTYPE_DEV_OR_BCE = 3;
 
 
/**
 * 初始状态
 *
 * @const
 * @type {number}
 */
const STATUS_INIT = 0;
 
/**
 * 获取开发者token中
 *
 * @const
 * @type {number}
 */
const STATUS_AUTHTYPE_REQESTING = 1;
 
/**
 * 获取开发者token成功,或者确定为云用户
 *
 * @const
 * @type {number}
 */
const STATUS_READY = 2;
 
/**
 * 非法ak,sk
 *
 * @const
 * @type {number}
 */
const STATUS_ERROR = -1;
 
 /**
 * BaseClient类
 * 各具体接口类基类,处理鉴权逻辑等
 *
 * @constructor
 * @param {string} appid appid.
 * @param {string} ak The access key.
 * @param {string} sk The security key.
 */
class BaseClient {
    constructor(appId, ak, sk, options) {
        this.appId = 0;
        this.ak = ak;
        this.sk = sk;
 
        this.options = options || {};
 
        this.authType = AUTHTYPE_INIT;
        this.status = STATUS_INIT;
 
        this.pms;
        this.devAccessToken = null;
 
        this.devAuth = new DevAuth(this.ak, this.sk);
 
        this.authTypeReq();
 
    }
    setAccessToken(token, expireTime) {
        let et = expireTime || DevAuthToken.DEFAULT_EXPIRE_DURATION;
        this.devAccessToken = new DevAuthToken(token, et, null);
        this.authType = AUTHTYPE_DEV;
        this.status = STATUS_READY;
    }
    authTypeReq() {
        // 请求access_token服务
        this.status = STATUS_AUTHTYPE_REQESTING;
        this.pms = this.devAuth.getToken().then(this.gotDevAuthSuccess.bind(this),
        this.gotDevAuthFail.bind(this));
        // 初始化client对象后立即发生的第一次异常,如果没有立即调用具体请求接口的话(必须有promise catch)
        // 将无法被捕获获取token的request网络异常,为了避免UnhandledPromiseRejectionWarning
        // 此处直接catch住,待代用具体接口时候再返回获取token时的异常,减少程序复杂度
        this.pms.catch(function (error) {
        }.bind(this));
        return this.pms;
    }
    gotDevAuthSuccess(token) {
        // 如果用户没有手动调用setAccessToken设置access_token
        if (this.authType !== AUTHTYPE_DEV) {
            this.devAccessToken = token;
            this.authType = AUTHTYPE_DEV_OR_BCE;
        }
        this.status = STATUS_READY;
    }
    gotDevAuthFail(err) {
        // 获取token时鉴权服务器返回失败信息
        if (err.errorType === DevAuth.EVENT_ERRTYPE_NORMAL) {
            // 可能是百度云的ak,sk
            this.authType = AUTHTYPE_BCE;
            this.status = STATUS_READY;
            return;
        }
 
        // 获取token时发生了网络错误
        // 或者是发生了服务器返回数据格式异常
        if (err.errorType === DevAuth.EVENT_ERRTYPE_NETWORK
            || err.errorType === DevAuth.EVENT_ERRTYPE_ILLEGAL_RESPONSE) {
            this.status = STATUS_ERROR;
            throw err;
        }
    }
    doRequest(requestInfo, httpClient) {
 
        // 如果获取token失败
        if (this.status === STATUS_ERROR) {
            this.authTypeReq();
        }
 
        return this.pms.then(function () {
            // 预检函数,返回是否token过期
            let isTokenExpired = this.preRequest(requestInfo);
 
            if (isTokenExpired === false) {
                // 鉴权方式确定,请求接口
                return httpClient.postWithInfo(requestInfo)
            } else {
                // 如果token过期了,说明是需要重新获取access_token
                // 待重新获取完后继续请求接口
                return this.pms.then(function () {
                    this.preRequest(requestInfo);
                    return httpClient.postWithInfo(requestInfo);
                }.bind(this))
            }
        }.bind(this));
    }
    checkDevPermission(requestInfo) {
        // 是否跳过这个检查(从speech.baidu.com创建的应用,调用语音接口需要跳过)
        if (this.options.isSkipScopeCheck === true) {
            return true;
        }
        // 检查是否拥有AI平台接口权限
        return this.devAccessToken.hasScope(requestInfo.scope);
    }
    preRequest(requestInfo) {
 
        // 获取access_token失败,使用百度云签名方式调用
        if (this.authType === AUTHTYPE_BCE) {
            requestInfo.makeBceOptions(this.ak, this.sk);
            return false;
        }
 
        // 获取access_token成功,或者调用setAccessToken设置的access_token
        if (this.authType === AUTHTYPE_DEV_OR_BCE || this.authType === AUTHTYPE_DEV) {
            // 拥有AI平台接口权限
            if (this.checkDevPermission(requestInfo) || this.authType === AUTHTYPE_DEV) {
 
                // 判断access_token是否过期
                if (!this.devAccessToken.isExpired()) {
                    requestInfo.makeDevOptions(this.devAccessToken);
                    return false;
                }
                // access_token过期重新获取
                this.authTypeReq();
                return true;
            } else {
                // 使用百度云签名方式访问调用
                requestInfo.makeBceOptions(this.ak, this.sk);
            }
        }
        return false;
    }
 }
 
module.exports = BaseClient;