C# 如何对接阿里云的机器批量翻译API

自己试了下对接没成功
签名算法用阿里提供的RPC,并通过了阿里官方DEMO,算法没问题
阿里云RPC OpenAPI请求的组成部分是怎样的_阿里云SDK-阿里云帮助中心
是看着官方API开发的
调用GetBatchTranslate批量翻译机器_机器翻译-阿里云帮助中心

然后我发现我怎么试都无法成功,总是提示时间戳失效?
我要怎么修改代码才能实现这个功能?不使用官方的SDK!

    public class Program {
        public static API信息 data;
        public static void Main(string[] args) {
            data = new API信息();
            data.KEY = "AccessKey ID";
            data.秘钥 = "AccessKey Secret ";
            data.源语言 = "en";
            data.目标语言 = "zh";
            string Json = HTTP批量机翻(new string[] { "hello", "world" });
            Console.WriteLine(Json);
            Console.ReadLine();
        }
        public static string HTTP批量机翻(string[] texts) {
            string url = "http://mt.cn-hangzhou.aliyuncs.com/api/translate/web/ecommerce?";
            string 请求类型 = "GET";
            //设置SourceText
            Dictionary<string, string> ID_文本 = new Dictionary<string, string>();
            int index = 0;
            foreach (string text in texts) {
                ID_文本.Add((index++).ToString(), text);
            }
            Dictionary<string, string> 请求参数 = new Dictionary<string, string>();
            //请求参数.Add("Action", "GetBatchTranslate");
            请求参数.Add("FormatType", "text");
            请求参数.Add("TargetLanguage", data.目标语言);
            请求参数.Add("SourceLanguage", data.源语言);
            请求参数.Add("Scene", "general");//专业版社交:social,通用版:general
            请求参数.Add("ApiType", "translate_standard");//通用版:translate_standard,专业版:translate_ecommerce
            请求参数.Add("SourceText", JsonConvert.SerializeObject(ID_文本));
            #region 计算公共请求参数
            Dictionary<string, string> 公共请求参数 = new Dictionary<string, string>();
            foreach (var kv in 请求参数) {
                公共请求参数.Add(kv.Key, kv.Value);
            }
            RFC3986 rfc = new RFC3986();
            公共请求参数.Add("Action", "GetBatchTranslate");
            公共请求参数.Add("Version", "2018-10-12");
            公共请求参数.Add("Format", "JSON");
            公共请求参数.Add("AccessKeyId", data.KEY);
            公共请求参数.Add("SignatureNonce", 随机数生成(14));
            公共请求参数.Add("Timestamp", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ"));
            公共请求参数.Add("SignatureMethod", "HMAC-SHA1");
            公共请求参数.Add("SignatureVersion", "1.0");
            #region 签名算法
            //首字母排序b,a,C => C,a,b,然后进行RFC3896的UTF-8编码
            Dictionary<string, string> 临时请求参数 = (from kv in 公共请求参数
                                                 orderby kv.Key[0], kv.Key
                                                 select kv).ToDictionary(t1 => rfc.编码(t1.Key), t2 => rfc.编码(t2.Value));
            StringBuilder 请求头 = new StringBuilder(url);
            StringBuilder 公共参数体 = new StringBuilder();
            for (int i = 0; i < 临时请求参数.Count; i++) {
                var kv = 临时请求参数.ElementAt(i);
                公共参数体.Append(kv.Key).Append("=").Append(kv.Value);
                if (i != 临时请求参数.Count - 1) {
                    公共参数体.Append("&");
                }
            }
            string 签名字符串 = $"{请求类型}&{rfc.编码("/")}&{rfc.编码(公共参数体.ToString())}";
            string signature = HMACSHA1加密(签名字符串, data.秘钥 + "&");//用秘钥加密签名串并返回BASE64
            #endregion
            公共请求参数.Add("Signature", signature);//请求签名
            #endregion
            StringBuilder 链接 = new StringBuilder(url);
            foreach (var kv in 请求参数) {
                链接.Append(kv.Key).Append('=').Append(kv.Value).Append('&');
            }
            for (int i = 0; i < 公共请求参数.Count; i++) {
                var kv = 公共请求参数.ElementAt(i);
                链接.Append(kv.Key).Append('=').Append(kv.Value);
                if (i != 公共请求参数.Count - 1) {
                    链接.Append("&");
                }
            }
            HttpWebRequest request = WebRequest.Create(链接.ToString()) as HttpWebRequest;
            request.KeepAlive = false;
            request.Method = 请求类型;
            request.Timeout = 6000;
            HttpWebResponse response;
            string 返回值 = null;
            try {
                using (response = (HttpWebResponse)request.GetResponse()) {
                    using (Stream myResponseStream = response.GetResponseStream()) {
                        using (StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"))) {
                            返回值 = myStreamReader.ReadToEnd();
                        }
                    }
                }
            } catch (Exception ex) {
                throw ex;
            } finally {
                request.Abort();
            }
            return 返回值;
        }

        /// <summary>
        /// HMACSHA1加密
        /// </summary>
        /// <param name="text">要加密的原串</param>
        ///<param name="key">私钥</param>
        /// <returns></returns>
        private static string HMACSHA1加密(string text, string key) {
            //HMACSHA1加密
            HMACSHA1 hmacsha1 = new HMACSHA1();
            hmacsha1.Key = System.Text.Encoding.UTF8.GetBytes(key);

            byte[] dataBuffer = System.Text.Encoding.UTF8.GetBytes(text);
            byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);

            return Convert.ToBase64String(hashBytes);

        }
        public static string 随机数生成(int 长度) {
            string buffer = "0123456789";// 随机字符中也可以为汉字(任何)
            StringBuilder sb = new StringBuilder();
            Random r = new Random();
            int range = buffer.Length;
            for (int i = 0; i < 长度; i++) {
                sb.Append(buffer.Substring(r.Next(range), 1));
            }
            return sb.ToString();
        }
    }
    public class API信息 {

        public string KEY { get; set; }
        public string 秘钥 { get; set; }
        public string 源语言 { get; set; }
        public string 目标语言 { get; set; }

    }
    public class RFC3986 {

        public string 编码(string str) {
            StringBuilder sb = new StringBuilder();
            var urf8Bytes = Encoding.UTF8.GetBytes(str);
            foreach (var item in urf8Bytes) {
                if (IsReverseChar((char)item)) {
                    sb.Append('%');
                    sb.Append(item.ToString("X2"));
                } else
                    sb.Append((char)item);
            }

            return sb.ToString();
        }

        private bool IsReverseChar(char c) {
            return !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
                    || c == '-' || c == '_' || c == '.' || c == '~');
        }
    }


# 根据您提供的代码,可能出现时间戳失效的原因是因为您在计算签名时使用了本地时间而不是UTC时间。

# 可以尝试将以下代码:

Timestamp = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ")

# 修改为:

Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")

# 另外,根据阿里云官方文档,HTTP请求的Content-Type应该为application/x-www-form-urlencoded,并将所有请求参数都放在请求体中进行传输。所以可以将请求参数序列化为字符串,再将其作为请求体进行传输。

# 以下是代码修改建议:

public static string HTTP批量机翻(string[] texts) {
    string url = "http://mt.cn-hangzhou.aliyuncs.com/api/translate/web/ecommerce";
    string 请求类型 = "POST"; // 修改为POST请求 
    //设置SourceText
    Dictionary<string, string> ID_文本 = new Dictionary<string, string>();
    int index = 0;
    foreach (string text in texts) {
        ID_文本.Add((index++).ToString(), text);
    }
    Dictionary<string, string> 请求参数 = new Dictionary<string, string>();
    //请求参数.Add("Action", "GetBatchTranslate");
    请求参数.Add("FormatType", "text");
    请求参数.Add("TargetLanguage", data.目标语言);
    请求参数.Add("SourceLanguage", data.源语言);
    请求参数.Add("Scene", "general");//专业版社交:social,通用版:general
    请求参数.Add("ApiType", "translate_standard");//通用版:translate_standard,专业版:translate_ecommerce
    请求参数.Add("SourceText", JsonConvert.SerializeObject(ID_文本));

    #region 计算公共请求参数
    Dictionary<string, string> 公共请求参数 = new Dictionary<string, string>();
    foreach (var kv in 请求参数)
    {
        公共请求参数.Add(kv.Key, kv.Value);
    }
    RFC3986 rfc = new RFC3986();
    公共请求参数.Add("Action", "GetBatchTranslate");
    公共请求参数.Add("Version", "2018-10-12");
    公共请求参数.Add("Format", "JSON");
    公共请求参数.Add("AccessKeyId", data.KEY);
    公共请求参数.Add("SignatureNonce", 随机数生成(14));
    公共请求参数.Add("Timestamp", DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")); // 使用UTC时间
    公共请求参数.Add("SignatureMethod", "HMAC-SHA1");
    公共请求参数.Add("SignatureVersion", "1.0");
    #region 签名算法
    //首字母排序b,a,C => C,a,b,然后进行RFC3896的UTF-8编码
    Dictionary<string, string> 临时请求参数 = (from kv in 公共请求参数
                                        orderby kv.Key[0], kv.Key
                                        select kv).ToDictionary(t1 => rfc.编码(t1.Key), t2 => rfc.编码(t2.Value));
    StringBuilder 请求头 = new StringBuilder(url);
    StringBuilder 公共参数体 = new StringBuilder();
    for (int i = 0; i < 临时请求参数.Count; i++)
    {
        var kv = 临时请求参数.ElementAt(i);
        公共参数体.Append(kv.Key).Append("=").Append(kv.Value);
        if (i != 临时请求参数.Count - 1)
        {
            公共参数体.Append("&");
        }
    }
    string 签名字符串 = $"{请求类型}&{rfc.编码("/")}&{rfc.编码(公共参数体.ToString())}";
    string signature = HMACSHA1加密(签名字符串, data.秘钥 + "&");//用秘钥加密签名串并返回BASE64
    #endregion
    公共请求参数.Add("Signature", signature);//请求签名
    #endregion

    // 将所有请求参数放在请求体中
    StringBuilder 请求体 = new StringBuilder();
    foreach (var kv in 请求参数)
    {
        请求体.Append(kv.Key).Append('=').Append(kv.Value).Append('&');
    }
    for (int i = 0; i < 公共请求参数.Count; i++)
    {
        var kv = 公共请求参数.ElementAt(i);
        请求体.Append(kv.Key).Append('=').Append(kv.Value);
        if (i != 公共请求参数.Count - 1)
        {
            请求体.Append("&");
        }
    }

    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
    request.KeepAlive = false;
    request.Method = 请求类型;
    request.Timeout = 6000;
    request.ContentType = "application/x-www-form-urlencoded"; // 设置Content-Type
    byte[] requestBody = Encoding.UTF8.GetBytes(请求体.ToString()); // 将请求体转换成字节数组
    request.ContentLength = requestBody.Length; // 设置请求体长度
    using (Stream requestStream = request.GetRequestStream())
    {
        requestStream.Write(requestBody, 0, requestBody.Length); // 将请求体写入请求流中
    }

    string 返回值 = null;
    try
    {
        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            using (Stream myResponseStream = response.GetResponseStream())
            {
                using (StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")))
                {
                    返回值 = myStreamReader.ReadToEnd();
                }
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        request.Abort();
    }
    return 返回值;
    }

# 希望这些修改能够帮助您成功调用阿里云机器翻译API。

建议先用HTTP请求工具调试通过了再用代码实现,同时注意调用的要求是否满足了:
1、调用接口QPS限制50,如有扩展需求,需联系客服
2、批量翻译单条字符长度上限是1000字符,一次最多可翻译50条,若超出上限,可以保存成文件,使用文档翻译
3、请确保在使用该接口前,已充分了解通用版和专业版翻译产品的收费方式和价格
4、批量翻译接口参考阿里云OpenAPI开发者门户调试调用

img

阿里 机器翻译 api
可以参考下这个例子


https://help.aliyun.com/document_detail/201590.html