实战解析:阿里云语音识别 Token 获取全流程
在对接阿里云语音识别(NLS)服务时,Token 是鉴权的核心凭证,所有语音交互请求都需要携带有效的 Token 才能正常调用。本文将从业务场景出发,逐段拆解阿里云语音识别 Token 的获取逻辑,并详解代码实现的核心要点,帮助开发者快速掌握 Token 获取的完整流程。

一、核心业务逻辑概述
阿里云语音识别 Token 的获取本质是通过 OpenAPI 调用 CreateToken 接口,完成签名认证后获取临时凭证,并通过缓存机制避免重复请求(Token 有有效期,默认 24 小时)。本文示例代码基于 Node.js + Egg.js 框架实现,核心流程可概括为:
- 从缓存中读取已存在的 Token,若存在则直接返回;
- 若缓存无 Token,则构造 API 请求参数并完成签名;
- 调用阿里云 Token 创建接口,获取 Token 后存入缓存;
- 返回 Token 及语音识别服务的基础配置(如服务地址、AppKey)。
二、代码逐段解析
2.1 缓存查询:优先使用已存在的 Token
async stToken() {
// 从 memcache 中获取缓存的 Token
let token = await this.ctx.service.memcache.get('aliyuncloud_nls_token');
if (typeof token === 'undefined') {
// 缓存无 Token 时,执行 Token 创建逻辑
// ... 后续 Token 创建代码
}
// 缓存有 Token 时,直接返回结果
this.ctx.body = {
code: 0,
success: true,
data: {
token,
url: 'wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1',
appkey: 'yFiBOd43tLhrTjH6',
},
message: '',
};
}关键说明 :
- 缓存 Key 命名为
aliyuncloud_nls_token,便于后续维护和排查; - 优先查询缓存是为了减少 API 调用次数,避免阿里云接口的限流风险,同时提升接口响应速度;
- 若缓存中
token为undefined(未缓存或已过期),则进入 Token 创建流程。
2.2 构造 API 请求参数:满足阿里云签名规范
const params = {
AccessKeyId: this.app.config.alioss.AccessKeyID, // 阿里云 AccessKey ID
Action: 'CreateToken', // 固定动作:创建 Token
Version: '2019-02-28', // API 版本,固定值
Format: 'JSON', // 返回格式,支持 JSON/XML
RegionId: 'cn-shanghai', // 地域 ID,语音识别默认上海
Timestamp: new Date().toISOString(), // 当前时间戳(ISO 格式)
SignatureMethod: 'HMAC-SHA1', // 签名算法,固定 HMAC-SHA1
SignatureVersion: '1.0', // 签名版本,固定 1.0
SignatureNonce: [
this.ctx.helper.random(8),
this.ctx.helper.random(4),
this.ctx.helper.random(4),
this.ctx.helper.random(4),
this.ctx.helper.random(12),
].join('-'), // 随机字符串,避免请求重放
};关键说明 :
AccessKeyId从配置文件读取,避免硬编码(生产环境需做好配置加密);SignatureNonce是随机字符串,通过分段随机拼接(8-4-4-4-12 格式),确保每次请求的唯一性,防止重放攻击;- 所有参数均为阿里云
CreateToken接口的必填项,参数名和取值需严格遵循阿里云 OpenAPI 规范。
2.3 参数规范化:按字母排序并 URL 编码
// 1) 按字母顺序规范化参数
const sortedKeys = Object.keys(params).sort();
const queryString = sortedKeys.map(key => `${percentEncode(key)}=${percentEncode(params[key])}`).join('&');关键说明 :
- 阿里云签名要求参数按 首字母升序排列 ,因此先通过
Object.keys(params).sort()获取排序后的参数名数组; percentEncode是 URL 编码函数(需自行实现,遵循 RFC3986 规范),对参数名和参数值分别编码,避免特殊字符导致签名错误;- 最终拼接成
key1=value1&key2=value2格式的查询字符串。
2.4 构造待签名字符串:签名的核心步骤
// 2) 构造待签名字符串
const stringToSign = `GET&${percentEncode('/')}&${percentEncode(queryString)}`;关键说明 :
- 阿里云 OpenAPI 签名规则为:
HTTP 方法&%2F&编码后的查询字符串(%2F是/的 URL 编码结果); - 因调用
CreateToken接口使用 GET 方法,故开头为GET&; - 需对
/和查询字符串分别编码后拼接,形成最终的待签名字符串。
2.5 计算签名:完成身份认证
// 3) 计算签名
const signature = signStringToSign(stringToSign, this.app.config.alioss.AccessKeySecret);关键说明 :
signStringToSign是签名函数,需基于 HMAC-SHA1 算法实现:
function signStringToSign(stringToSign, accessKeySecret) {
const crypto = require('crypto');
const key = accessKeySecret + '&'; // 阿里云签名密钥需拼接&
const hmac = crypto.createHmac('sha1', key);
return hmac.update(Buffer.from(stringToSign, 'utf8')).digest('base64');
}AccessKeySecret是阿里云账号的密钥,需严格保密,切勿泄露或提交到代码仓库;- 签名结果需进行 Base64 编码,得到最终的
signature。
2.6 拼接请求 URL 并调用接口:获取 Token
// 4) 拼接到完整 URL
const url = `https://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${signature}&${queryString}`;
const res = await this.ctx.curl(url, { method: 'get', dataType: 'json' }).catch(err => {
this.ctx.returnError(err.message);
});关键说明 :
- 请求域名
nls-meta.cn-shanghai.aliyuncs.com是阿里云语音识别元数据服务的固定域名(上海地域); - URL 拼接规则:基础域名 +
?Signature=签名值&原查询字符串; - 使用 Egg.js 内置的
ctx.curl发起 GET 请求,指定dataType: 'json'自动解析返回结果; - 增加异常捕获,若请求失败则通过
ctx.returnError返回错误信息。
2.7 处理返回结果:缓存 Token 并返回
res.data = res.data || {};
if ('Token' in res.data) {
token = res.data.Token;
// 将 Token 存入缓存,设置过期时间(提前 1 小时过期,避免使用时已失效)
await this.ctx.service.memcache.set(
'aliyuncloud_nls_token',
res.data.Token,
Number(res.data.Token.ExpireTime + '000') - new Date().getTime() - 3600,
);
} else {
this.ctx.returnError(res.data.ErrMsg || res.data.Message || '获取 token 出错了');
}关键说明 :
- 阿里云返回的
res.data.Token包含Id(Token 值)、ExpireTime(过期时间,单位秒)等信息; - 缓存过期时间设置为
Token 过期时间 - 当前时间 - 3600 秒,提前 1 小时过期,避免因网络延迟等问题使用到过期 Token; - 若返回结果无
Token字段,优先返回阿里云的错误信息(ErrMsg/Message),便于问题排查。
2.8 返回最终结果:提供语音识别所需配置
this.ctx.body = {
code: 0,
success: true,
data: {
token,
url: 'wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1', // 语音识别 WebSocket 地址
appkey: 'yFiBOd43tLhrTjH6', // 阿里云语音识别应用 AppKey
},
message: '',
};关键说明 :
- 返回格式包含
code(状态码)、success(是否成功)、data(核心数据)、message(提示信息),符合通用接口规范; url是阿里云语音识别的 WebSocket 服务地址(上海地域),appkey是创建语音识别应用时生成的应用密钥,需替换为自身的 AppKey。
三、完整代码(含辅助函数)
为方便开发者直接使用,以下是补充辅助函数后的完整代码:
// 实现 RFC3986 规范的 URL 编码
function percentEncode(str) {
return encodeURIComponent(str)
.replace(/!/g, '%21')
.replace(/'/g, '%27')
.replace(/\(/g, '%28')
.replace(/\)/g, '%29')
.replace(/\*/g, '%2A');
}
// 计算阿里云 API 签名
function signStringToSign(stringToSign, accessKeySecret) {
const crypto = require('crypto');
const key = accessKeySecret + '&';
const hmac = crypto.createHmac('sha1', key);
return hmac.update(Buffer.from(stringToSign, 'utf8')).digest('base64');
}
async stToken() {
let token = await this.ctx.service.memcache.get('aliyuncloud_nls_token');
if (typeof token === 'undefined') {
const params = {
AccessKeyId: this.app.config.alioss.AccessKeyID,
Action: 'CreateToken',
Version: '2019-02-28',
Format: 'JSON',
RegionId: 'cn-shanghai',
Timestamp: new Date().toISOString(),
SignatureMethod: 'HMAC-SHA1',
SignatureVersion: '1.0',
SignatureNonce: [
this.ctx.helper.random(8),
this.ctx.helper.random(4),
this.ctx.helper.random(4),
this.ctx.helper.random(4),
this.ctx.helper.random(12),
].join('-'),
};
// 1) 按字母顺序规范化参数
const sortedKeys = Object.keys(params).sort();
const queryString = sortedKeys.map(key => `${percentEncode(key)}=${percentEncode(params[key])}`).join('&');
// 2) 构造待签名字符串
const stringToSign = `GET&${percentEncode('/')}&${percentEncode(queryString)}`;
// 3) 计算签名
const signature = signStringToSign(stringToSign, this.app.config.alioss.AccessKeySecret);
// 4) 拼接到完整 URL
const url = `https://nls-meta.cn-shanghai.aliyuncs.com/?Signature=${signature}&${queryString}`;
const res = await this.ctx.curl(url, { method: 'get', dataType: 'json' }).catch(err => {
this.ctx.returnError(err.message);
});
res.data = res.data || {};
if ('Token' in res.data) {
token = res.data.Token;
// 缓存 Token,提前 1 小时过期
await this.ctx.service.memcache.set(
'aliyuncloud_nls_token',
res.data.Token,
Number(res.data.Token.ExpireTime + '000') - new Date().getTime() - 3600,
);
} else {
this.ctx.returnError(res.data.ErrMsg || res.data.Message || '获取 token 出错了');
}
}
this.ctx.body = {
code: 0,
success: true,
data: {
token,
url: 'wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1',
appkey: 'yFiBOd43tLhrTjH6', // 替换为自身的 AppKey
},
message: '',
};
}四、注意事项
- AccessKey 安全 :
AccessKeyID和AccessKeySecret需从阿里云 RAM 控制台创建子账号获取,避免使用主账号密钥,且需配置最小权限(仅允许调用CreateToken接口); - 缓存可靠性 :若缓存服务异常,需确保代码能降级重新获取 Token,避免服务不可用;
- 地域一致性 :
RegionId、请求域名、WebSocket 地址需保持地域一致(如上海地域均为cn-shanghai); - 异常监控 :需对 Token 获取失败的情况增加日志记录和告警,便于及时发现问题。
总结
- 阿里云语音识别 Token 获取的核心是遵循 OpenAPI 签名规范,完成参数排序、编码、签名三步核心操作;
- 缓存 Token 可减少 API 调用次数,提升服务性能,缓存过期时间需提前 1 小时避免使用失效 Token;
- 代码实现需注意 AccessKey 安全、异常处理、地域一致性三大要点,确保 Token 获取稳定可靠。
通过本文的解析,开发者可快速掌握阿里云语音识别 Token 的获取逻辑,并基于示例代码适配自身业务场景,完成语音识别服务的对接。
发布评论
发布评论前请先 登录。
评论列表 0

暂无评论



