You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET中无SDK调用AWS TranslateText并添加Signature V4签名?

解决.NET环境下直接调用AWS TranslateText REST API的问题

最近在.NET里尝试不用SDK直接调用AWS TranslateText的REST API,踩了好几个坑,跟大家分享下解决过程和可用的代码:

  • 一开始以为是Signature V4签名生成错误,用Postman验证后排除了这个可能
  • 后来发现问题出在缺少必填的请求头x-amz-target,它的有效值必须是AWSShineFrontendService_20170701.TranslateText

下面是经过验证可以正常运行的.NET实现代码,替换掉自己的AccessKey和SecretKey就能用:

using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web.Script.Serialization;

namespace AWS_TranslateTextTest
{
    class AWS_TranslateText
    {
        // Replace this with your own values
        const string AccessKey = "AKI_ADD_YOUR_ACCESSKEY";
        const string SecretKey = "ADD_YOUR_SECRETKEY";

        static void Main()
        {
            try
            {
                string text = "Translate this text from English to German.";
                string sourceLang = "en";
                string targetLang = "de";

                string responseText = TranslateText(text, sourceLang, targetLang);
                JObject json = JObject.Parse(responseText);
                string translatedText = "";

                // Read response from json
                if (json.ToString().Contains("TranslatedText"))
                {
                    dynamic obj = json;
                    translatedText = obj.TranslatedText.Value;
                    Console.WriteLine("TranslatedText is: {0}", translatedText);
                }
                else
                {
                    Console.WriteLine("TranslatedText not found in response.");
                    throw new Exception(json.ToString());
                }
            }
            catch (WebException ex)
            {
                Console.WriteLine(ex.Message);
                if (ex.Response != null)
                {
                    foreach (string header in ex.Response.Headers)
                    {
                        Console.WriteLine("{0}: {1}", header, ex.Response.Headers[header]);
                    }
                    using (var responseStream = ex.Response.GetResponseStream())
                    {
                        if (responseStream != null)
                        {
                            using (var streamReader = new StreamReader(responseStream))
                            {
                                Console.WriteLine(streamReader.ReadToEnd());
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private static string TranslateText(string text, string sourceLang, string targetLang)
        {
            var date = DateTime.UtcNow;
            const string algorithm = "AWS4-HMAC-SHA256";
            const string regionName = "eu-west-1";
            const string serviceName = "translate";
            const string method = "POST";
            const string canonicalUri = "/";
            const string canonicalQueryString = "";
            const string x_amz_target_header = "AWSShineFrontendService_20170701.TranslateText";
            const string contentType = "application/x-amz-json-1.1";
            const string host = serviceName + "." + regionName + ".amazonaws.com";

            var obj = new
            {
                SourceLanguageCode = sourceLang,
                TargetLanguageCode = targetLang,
                Text = text
            };

            var requestPayload = new JavaScriptSerializer().Serialize(obj);
            var hashedRequestPayload = HexEncode(Hash(ToBytes(requestPayload)));

            var dateStamp = date.ToString("yyyyMMdd");
            var requestDate = date.ToString("yyyyMMddTHHmmss") + "Z";
            var credentialScope = string.Format("{0}/{1}/{2}/aws4_request", dateStamp, regionName, serviceName);

            var bytes = ToBytes(requestPayload);
            var headers = new SortedDictionary<string, string>
            {
                {"content-length", bytes.Length.ToString()},
                {"content-type", contentType},
                {"host", host},
                {"x-amz-date", requestDate},
                {"x-amz-target", x_amz_target_header}
            };

            string canonicalHeaders = string.Join("\n", headers.Select(x => x.Key.ToLowerInvariant() + ":" + x.Value.Trim())) + "\n";
            string signedHeaders = string.Join(";", headers.Select(x => x.Key.ToLowerInvariant()));

            // Task 1: Create a Canonical Request For Signature Version 4
            var canonicalRequest = method + '\n' +
                                   canonicalUri + '\n' +
                                   canonicalQueryString + '\n' +
                                   canonicalHeaders + '\n' +
                                   signedHeaders + '\n' +
                                   hashedRequestPayload;

            var hashedCanonicalRequest = HexEncode(Hash(ToBytes(canonicalRequest)));

            // Task 2: Create a String to Sign for Signature Version 4
            var stringToSign = string.Format("{0}\n{1}\n{2}\n{3}",
                algorithm,
                requestDate,
                credentialScope,
                hashedCanonicalRequest);

            // Task 3: Calculate the Signature for AWS Signature Version 4
            var signingKey = GetSignatureKey(SecretKey, dateStamp, regionName, serviceName);
            var signature = HexEncode(HmacSha256(signingKey, ToBytes(stringToSign)));

            // Task 4: Prepare the Authorization Header
            var authorizationHeader = string.Format("{0} Credential={1}/{2}, SignedHeaders={3}, Signature={4}",
                algorithm,
                AccessKey,
                credentialScope,
                signedHeaders,
                signature);

            // Create the request
            var request = (HttpWebRequest)WebRequest.Create("https://" + host);
            request.Method = method;
            request.ContentType = contentType;
            request.Headers.Add("x-amz-date", requestDate);
            request.Headers.Add("x-amz-target", x_amz_target_header);
            request.Headers.Add("Authorization", authorizationHeader);

            // Write the payload
            using (var streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                streamWriter.Write(requestPayload);
            }

            // Get the response
            using (var response = (HttpWebResponse)request.GetResponse())
            using (var streamReader = new StreamReader(response.GetResponseStream()))
            {
                return streamReader.ReadToEnd();
            }
        }

        // Helper methods for hashing and encoding
        private static byte[] ToBytes(string str)
        {
            return Encoding.UTF8.GetBytes(str);
        }

        private static byte[] Hash(byte[] bytes)
        {
            using (var sha256 = SHA256.Create())
            {
                return sha256.ComputeHash(bytes);
            }
        }

        private static string HexEncode(byte[] bytes)
        {
            var sb = new StringBuilder();
            foreach (byte b in bytes)
            {
                sb.Append(b.ToString("x2"));
            }
            return sb.ToString();
        }

        private static byte[] HmacSha256(byte[] key, byte[] data)
        {
            using (var hmac = new HMACSHA256(key))
            {
                return hmac.ComputeHash(data);
            }
        }

        private static byte[] GetSignatureKey(string key, string dateStamp, string regionName, string serviceName)
        {
            var kSecret = ToBytes("AWS4" + key);
            var kDate = HmacSha256(kSecret, ToBytes(dateStamp));
            var kRegion = HmacSha256(kDate, ToBytes(regionName));
            var kService = HmacSha256(kRegion, ToBytes(serviceName));
            var kSigning = HmacSha256(kService, ToBytes("aws4_request"));
            return kSigning;
        }
    }
}

注意事项

  • 务必替换代码中的AccessKey和SecretKey为你自己的AWS凭证
  • 代码默认使用eu-west-1区域,如果你的Translate服务部署在其他区域,需要修改regionName变量

内容的提问来源于stack exchange,提问作者Cristina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:15:09