Я пытаюсь запросить API книг Amazon Web Service (AWS) в С#. Я не читал связанные сообщения в Stackoverflow. Я все еще получаю сообщение об ошибке: "Удаленный сервер ответил на ошибку: (403) Запрещено". Я закодировал все + и =. Что я делаю неправильно здесь, пожалуйста?
public const string ACCESSKEY = "xxxxx"; // Replace with Actual Access Key
public const string SECRETKEY = "zzzzz"; // Replace with Actual Secret Key
public void ProcessRequest(HttpContext context)
{
string ts = DateTime.UtcNow.ToString("s");
string url = "http://webservices.amazon.com/onca/xml?";
string req = "AWSAccessKeyId=" + ACCESSKEY + "&Condition=All&IdType=ASIN&ItemId=B00008OE6I&Operation=ItemLookup&ResponseGroup=OfferFull&Service=AWSECommerceService";
req = req + "&Timestamp=" + URLEncode(ts + "Z").ToUpper();
string s = "GET\nwebservices.amazon.com\n/onca/xml\n" + req;
Util.Write(s);
Util.Write("");
string hash = HashString(s);
req = req + "&Signature=" + hash;
url = url + req;
Util.Write(url);
Util.Write("");
string blob = XGetBlobAtURL(url);
Util.Write(blob);
}
private string URLEncode(string s)
{
return(HttpContext.Current.Server.UrlEncode(s));
}
private string XGetBlobAtURL(string url, string useragent = "")
{
string blob = "";
try
{
WebClient wc = new WebClient();
if (!Util.IsEmpty(useragent)) { wc.Headers["User-Agent"] = useragent; }
blob = wc.DownloadString(url);
wc.Dispose();
}
catch(Exception e)
{
Util.Write(e.ToString());
}
return (blob);
}
private string HashString(string s)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(URLEncode(SECRETKEY));
HMACSHA256 hmasha256 = new HMACSHA256(keyByte);
byte[] messageBytes = encoding.GetBytes(s);
byte[] hashmessage = hmasha256.ComputeHash(messageBytes);
string s2 = ByteToString(hashmessage);
return (URLEncode(s2));
}
private string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
Решение от OP.
Я понял, что я делаю неправильно. Мне пришлось: Base64 закодировать хэш HMASHA256, добавить отсутствующие поля в строке запроса в Amazon Book API и прописать верхний регистр URLEncoded% XX без верхнего конца остальной строки. Код, указанный ниже, теперь работает и соответствует документации Amazon по адресу: http://docs.aws.amazon.com/AWSECommerceService/latest/DG/rest-signature.html
public const string ACCESSKEY = "xxxxx";
public const string SECRETKEY = "zzzzz";
public const string TAG = "ccccc";
private XmlDocument XML;
public void ProcessRequest(HttpContext context)
{
string ts = DateTime.UtcNow.ToString("s");
string url = "http://webservices.amazon.com/onca/xml?";
string req = "AWSAccessKeyId=" + ACCESSKEY + "&AssociateTag=" + TAG;
// Search by ISBN:
req = req + "&Condition=All&IdType=ISBN&ItemId=0596004923&Operation=ItemLookup&ResponseGroup=Small&SearchIndex=Books&Service=AWSECommerceService";
string tsq = "&Timestamp=" + URLEncode(ts + "Z").ToUpper();
string s = "GET\nwebservices.amazon.com\n/onca/xml\n" + req + tsq;
string hash = HashString(s);
req = req + tsq + "&Signature=" + hash;
url = url + req;
ReadXML(url);
WriteXML();
}
private void ReadXML(string url)
{
XML = new XmlDocument();
XML.Load(url);
}
private void WriteXML()
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "text/xml";
HttpContext.Current.Response.CacheControl = "no-cache";
HttpContext.Current.Response.Write(XML.OuterXml);
HttpContext.Current.Response.End();
}
private string UCaseUrlEncode(string s)
{
char[] x = HttpUtility.UrlEncode(s).ToCharArray();
for (int i = 0; i < x.Length - 2; i++)
{
if (x[i] == '%')
{
x[i+1] = char.ToUpper(x[i+1]);
x[i+2] = char.ToUpper(x[i+2]);
}
}
return new string(x);
}
private string URLEncode(string s)
{
return(HttpContext.Current.Server.UrlEncode(s));
}
private string URLDecode(string s)
{
return (HttpContext.Current.Server.UrlDecode(s));
}
private string HashString(string s)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(SECRETKEY);
byte[] messageBytes = encoding.GetBytes(s);
HMACSHA256 hmasha256 = new HMACSHA256(keyByte);
byte[] hashmessage = hmasha256.ComputeHash(messageBytes);
return (UCaseUrlEncode(Convert.ToBase64String(hashmessage)));
}
private string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}