我在使用Aliyun 阿里云 ACS 机器翻译时遇到了SignatureDoesNotMatch 再次记录一下我的解决办法 也为其他遇到同样问题的伙伴指路
总体上来说阿里的文档做的不好,因此遇到不少困难,解决起来也不容易
阿里的介绍页
https://www.aliyun.com/product/ai/base_alimt?spm=5176.15007269.0.0.5e305d78mw1Tea
首先开通机器翻译服务
https://mt.console.aliyun.com/basic
开通一个通用版翻译引擎 和 专业版翻译引擎
然后去控制台 > 访问控制 https://ram.console.aliyun.com/overview 建立子账号和 AccessKey,这里的Key密码只显示一次 一定要保存好
权限策略管理 加一个 规则
再把这个规则 授权 给刚建立的AccessKey
{
"Statement": [
{
"Effect": "Allow",
"Action": "alimt:*",
"Resource": "*"
}
],
"Version": "1"
}
关键的 开发指南
https://help.aliyun.com/document_detail/158244.html?spm=a2c4g.11186623.6.554.35c86720EBjoMf
其实只看上面的就可以 下面是重复的 应该删掉
请求参数
名称 | 示例值 | 描述 |
---|---|---|
Action | TranslateGeneral | 系统规定参数。取值:TranslateGeneral。 |
FormatType | text | 翻译文本的格式,html( 网页格式。设置此参数将对待翻译文本以及翻译后文本按照html格式进行处理)、text(文本格式。设置此参数将对传入待翻译文本以及翻译后结果不做文本格式处理,统一按纯文本格式处理。 |
Scene | general | 通用版本默认是:general,医疗(medical),社交(social) |
SourceLanguage | en | 原文语言 |
TargetLanguage | zh | 需要翻译的内容 |
SourceText | Hello World! | 待翻译文本 |
返回数据
名称 | 类型 | 示例值 | 描述 |
---|---|---|---|
Code | Integer | 200 | 错误码 |
Data | Struct | 封装了返回的翻译结果 | |
Translated | String | 你好世界 | 翻译结果 |
Message | String | success | 返回信息 |
RequestId | GUID | 86D18195-D89C-4C8C-9DC4-5FCE789CE6D5 | 请求ID |
也是比较清晰的 ,然后就是httprequest的签名算法, 一般的机器翻译基本上都采用类似Google的随机数加APIKey加待翻译文字的算法,但是阿里不太一样,有一套自己的签名算法https://help.aliyun.com/document_detail/108552.html?spm=a2c4g.11186623.6.552.5ae042e0XtV1jT
而且这套算法是全阿里平台通用的 并且不包含待翻译文字
可以通过文档页面和Open API进行调试 这一点很方便
https://api.aliyun.com/#/?product=alimt&api=TranslateGeneral
页面直接测试还给出了HTTP响应以及生成了代码
给出的代码如下 .NET
using System;
using System.Collections.Generic;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.alimt.Model.V20181012;
namespace alimtDemo
{
class Program
{
static void Main(string[] args)
{
IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", "<accessKeyId>", "<accessSecret>");
DefaultAcsClient client = new DefaultAcsClient(profile);
var request = new TranslateGeneralRequest();
request.FormatType = "text";
request.SourceLanguage = "en";
request.TargetLanguage = "zh";
request.SourceText = "Hello World!";
try {
var response = client.GetAcsResponse(request);
Console.WriteLine(System.Text.Encoding.Default.GetString(response.HttpResponse.Content));
}
catch (ServerException e)
{
Console.WriteLine(e);
}
catch (ClientException e)
{
Console.WriteLine(e);
}
}
}
}
接下来换在IDE中测试
首先 GitHub下载SDK
https://github.com/aliyun/aliyun-openapi-net-sdk
需要 aliyun-net-sdk-alimt 和 aliyun-net-sdk-core
编译后得到aliyun-net-sdk-alimt.dll和aliyun-net-sdk-core.dll (编译时需要newtonsoft json)
运行上面的源码,你就会得到 SignatureDoesNotMatch 的错误
节约时间原因我就不多说了 解决方法如下:
var request = new TranslateGeneralRequest(); 之后
- 添加 request.Method = Aliyun.Acs.Core.Http.MethodType.POST;
- 添加 request.ActionName = “TranslateGeneral”;
其实从上面的参数表里面我们已经看到Action是一个必要的参数,因此必须明确声明,但是阿里的页面调试器默认赋值了这个参数 因此 在线版不会错 但是IDE测试出错
同理默认httprequest是GET,阿里机器翻译API只接受POST
添加后编译通过得到结果是一个byte[]数组 用UTF-8转换得到
{
"RequestId": "75D29BFF-9D06-4069-B35A-BFA41DF2C075",
"Data": {
"Translated": "你好世界!"
},
"Code": "200"
}
用json转换一下
dynamic TempResult = JsonConvert.DeserializeObject(resultStr);
string resultText = Convert.ToString(TempResult["Data"]["Translated"]);
得到最终翻译结果
最后完整代码
using System;
using System.Collections.Generic;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.alimt.Model.V20181012;
using Newtonsoft.Json;
namespace alimtDemo
{
class Program
{
static void Main(string[] args)
{
IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", "<accessKeyId>", "<accessSecret>");
DefaultAcsClient client = new DefaultAcsClient(profile);
var request = new TranslateGeneralRequest();
request.FormatType = "text";
request.SourceLanguage = "en";
request.TargetLanguage = "zh";
request.SourceText = "Hello World!";
request.Scene = "general";
request.Method = Aliyun.Acs.Core.Http.MethodType.POST;
request.ActionName = "TranslateGeneral";
try {
var response = client.GetAcsResponse(request);
string resultStr = System.Text.Encoding.UTF-8.GetString(response.HttpResponse.Content);
dynamic TempResult = JsonConvert.DeserializeObject(resultStr);
string resultText = Convert.ToString(TempResult["Data"]["Translated"]);
Console.WriteLine(resultText);
Console.ReadLine();
}
catch (ServerException e)
{
Console.WriteLine(e);
}
catch (ClientException e)
{
Console.WriteLine(e);
}
}
}
}