当您在调用有道翻译API时遇到“签名错误”(通常对应错误码110),这几乎总是意味着您在生成请求签名(sign)时出现了偏差。签名错误的核心原因在于签名字符串的拼接顺序、参数值的准确性或哈希算法的应用。最常见的问题包括:应用密钥(appKey/appSecret)填写错误、查询文本(q)未按规则截取、时间戳(curtime)格式不正确,或是拼接各个参数的顺序与官方文档不符。请仔细核对签名生成的每一个环节,确保与官方要求完全一致。

什么是有道翻译API的签名(Sign)?
在有道翻译API的调用过程中,签名(sign)是一个至关重要的安全凭证。它的主要作用是验证请求的合法性和完整性,确保API调用是由授权的开发者发起的,并且传输过程中的数据没有被篡改。每一次API请求都必须携带一个动态生成的签名,服务端会用同样的方式计算签名并进行比对,若比对一致,则请求被视为有效。

这个机制依赖于您在有道智云平台上获取的专属应用ID(appKey)和应用密钥(appSecret)。AppKey是公开的身份标识,而appSecret是私密的,必须妥善保管,绝不能泄露。签名的生成过程结合了您的私密密钥和请求的动态参数,从而构成了一道坚固的安全防线,保护您的应用和数据安全。

如何正确生成签名(Sign)?
精确地生成签名是成功调用API的前提。签名是通过将多个参数值按特定顺序拼接成一个字符串,然后对该字符串进行SHA256哈希运算得到的。正确的签名生成公式如下:
sign = SHA256(appKey + truncate(q) + salt + curtime + appSecret)
这个公式中的每一个组成部分都必须完全正确,包括大小写、编码和截取规则。任何微小的差异都会导致最终的哈希值不同,从而引发“签名错误”。
签名参数详解
为了帮助您更好地理解签名生成过程,下表详细列出了所有参与签名计算的参数及其具体要求:
| 参数 | 说明 | 注意事项 |
|---|---|---|
appKey |
应用ID。您在有道智云平台创建应用后获得的唯一身份标识。 | 请直接复制,不要添加任何多余的字符或空格。 |
q |
待翻译文本。需要进行翻译的UTF-8编码字符串。 | 在参与签名计算时,需要遵循特殊的截取规则(见下文)。 |
salt |
随机字符串。用于增加签名的随机性,防止重放攻击。 | 建议使用UUID。每次请求的salt值应不同。 |
curtime |
当前UTC时间戳。以秒为单位的Unix时间戳。 | 务必使用秒级时间戳,而非毫秒。同时请确保您的服务器时间与标准时间同步。 |
appSecret |
应用密钥。与appKey配对的私密密钥,用于签名计算。 | 绝对不能泄露。请从平台完整复制,确保无误。 |
什么是查询字符串(q)的特殊截取规则?
查询字符串(q)在参与签名计算时,有一个特殊的处理规则,这是开发者最容易忽略的细节之一。这个规则被称为truncate(q),具体逻辑如下:
- 如果待翻译文本
q的长度小于或等于20个字符,则truncate(q)就是q本身。 - 如果待翻译文本
q的长度大于20个字符,则truncate(q)的处理方式为:q的前10个字符 +q的长度 +q的后10个字符。
例如,假设待翻译文本q为 "Supercalifragilisticexpialidocious"(长度为34),那么参与签名的truncate(q)应该是 "Supercalif34lidocious"。
导致“签名错误”(错误码110)的常见原因是什么?
当您确认了签名生成的基本规则后,可以对照以下常见错误点进行逐一排查。绝大多数的签名问题都源于这些细节疏漏。
您的应用密钥(AppKey)或应用秘钥(AppSecret)是否正确?
这是最基础也是最常见的错误。请登录有道智云控制台,仔细核对您代码中填写的appKey和appSecret。检查重点:
- 复制粘贴错误:是否在复制时遗漏了字符,或者包含了额外的空格、换行符?
- 密钥混淆:是否将
appKey和appSecret的位置填反了? - 环境配置问题:如果您使用环境变量或配置文件,请确认加载的值是正确的,尤其是在测试环境和生产环境切换时。
查询字符串(q)的截取或编码是否出错?
查询文本q的处理是第二大易错点。请确认以下两点:
- 编码格式:所有输入文本在参与计算前,必须是UTF-8编码。如果您的源文件编码不是UTF-8,可能会在计算字符长度或截取时产生错误。
- 截取规则:务必严格按照上文提到的
truncate(q)规则进行处理。可以手动计算一次,与程序生成的值进行比对。
Salt和Curtime参数是否符合规范?
时间和随机数是确保签名动态性的关键。这两个参数的错误同样会导致验证失败。
- `salt`:虽然可以是任意字符串,但强烈建议使用标准的UUID库来生成,以保证其唯一性和随机性。每次API请求的
salt都应该是不同的。 - `curtime`:必须是以秒为单位的Unix时间戳。很多编程语言的内置时间函数默认返回毫秒级时间戳(例如Java的
System.currentTimeMillis()或JavaScript的Date.now()),您需要将其除以1000并取整。此外,请检查您发起请求的服务器系统时间是否准确。
拼接字符串的顺序是否颠倒?
签名原始字符串的拼接顺序是固定的,不容更改。正确的顺序是:
appKey + truncate(q) + salt + curtime + appSecret
请在代码中打印出拼接后的完整字符串,并与此顺序进行严格比对。任何参数位置的调换都会生成完全不同的签名。
SHA256哈希算法是否应用正确?
在得到拼接后的原始字符串后,最后一步是进行SHA256哈希计算。请确保您的哈希函数库是标准的,并且输出的哈希结果是小写的32字节(64位)十六进制字符串。一些哈希库可能默认输出大写或二进制格式,这需要您手动进行转换。
如何通过代码示例进行排查?
理论结合实践是解决问题的最佳途径。以下是有道官方提供的、在几种主流编程语言中正确生成签名的代码示例。您可以直接参考或用于比对自己代码的实现逻辑。
Python 签名生成示例
import hashlib
import time
import uuid
def encrypt(sign_str):
hash_algorithm = hashlib.sha256()
hash_algorithm.update(sign_str.encode("utf-8"))
return hash_algorithm.hexdigest()
def truncate(q):
if q is None:
return None
size = len(q)
return q if size <= 20 else q[0:10] + str(size) + q[size - 10:size]
def generate_sign(app_key, app_secret, q):
salt = str(uuid.uuid1())
curtime = str(int(time.time()))
# 拼接原始字符串
sign_str = app_key + truncate(q) + salt + curtime + app_secret
# 计算签名
sign = encrypt(sign_str)
return sign, salt, curtime
Java 签名生成示例
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
public class AuthV3Util {
public static String getDigest(String string) {
if (string == null) {
return null;
}
char[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
try {
MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char[] str = new char[j * 2];
int k = 0;
for (byte byte0 : md) {
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
public static String truncate(String q) {
if (q == null) {
return null;
}
int len = q.length();
return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
}
// 调用示例
// String appKey = "您的appKey";
// String appSecret = "您的appSecret";
// String q = "待翻译的文本";
// String salt = UUID.randomUUID().toString();
// String curtime = String.valueOf(System.currentTimeMillis() / 1000);
// String signStr = appKey + truncate(q) + salt + curtime + appSecret;
// String sign = getDigest(signStr);
}
JavaScript (Node.js) 签名生成示例
const crypto = require("crypto");
const { v4: uuidv4 } = require("uuid");
function truncate(q) {
const len = q.length;
if (len <= 20) return q;
return q.substring(0, 10) + len + q.substring(len - 10, len);
}
function generateSign(appKey, appSecret, q) {
const salt = uuidv4();
const curtime = Math.round(new Date().getTime() / 1000);
const qInSign = truncate(q);
const str = appKey + qInSign + salt + curtime + appSecret;
const sign = crypto.createHash("sha256").update(str).digest("hex");
return {
sign,
salt,
curtime
};
}
我该如何使用调试工具自查问题?
当自动化代码无法正常工作时,采用“打印调试法”是定位问题的最有效手段。请按照以下步骤进行自我诊断:
- 打印所有参数:在拼接字符串之前,将
appKey,q,salt,curtime, 和appSecret的值分别打印到控制台。检查它们是否符合预期,特别是curtime是否是10位数的秒级时间戳。 - 打印截取后的q:单独打印
truncate(q)的执行结果,确保它符合截取规则。 - 打印拼接后的原始字符串:将
appKey + truncate(q) + salt + curtime + appSecret这个最终拼接的字符串完整打印出来。这是进行哈希前的“原材料”,是排查问题的关键。 - 手动验证哈希:复制上一步打印出的原始字符串,使用一个在线的SHA256哈希计算工具(搜索 "SHA256 online" 即可找到),将字符串粘贴进去进行计算。将在线工具生成的结果与您代码生成的
sign值进行比对。如果二者不一致,说明您的哈希函数实现或输出格式有误;如果一致但仍然报签名错误,说明问题出在拼接前的某个参数值上。
通过这个过程,您几乎可以百分之百地定位到问题的根源。
除了翻译,有道智云还提供哪些服务?
成功解决API调用问题后,您或许有兴趣了解,有道翻译API仅仅是庞大的有道智云(Youdao AI Cloud)能力矩阵中的一部分。有道智云致力于为全球开发者和企业提供领先的人工智能技术服务,构建了涵盖四大领域的AI能力体系。
除了强大的语言翻译能力,我们还提供:
- 文字识别(OCR):支持印刷体、手写体、各类卡证票据的高精度识别,助力企业实现文档自动化处理。
- 智能语音(ASR/TTS):提供高质量的语音识别、语音合成、语音情感分析等服务,赋能智能客服、在线教育和物联网设备。
- 自然语言处理(NLP):包括情感分析、文本纠错、关键词提取等,帮助您深度理解和处理文本数据。
通过有道智云统一的平台和API接口,您可以轻松地将这些顶尖的AI能力集成到您的应用中,创造出更智能、更强大的产品体验。
