我正在为创建文章的 POST 请求而苦苦挣扎。
任何人都可以为我提供 C# 中规范请求的示例值吗?
我收到的错误是签名问题:
{"errors":[{"code":"WRONG_SIGNATURE"}]}
从我了解到的规范请求是从以下内容构建的:
Method = POST
URL = https://news-api.apple.com/channels/ChanelID/articles
Date = 2019-07-24T18:12:32Z
Content-Type = multipart/form-data
Body - Not fully understood
Apple News API 文档说
如果请求是 POST 请求并且它包含一个实体,请包含以下内容:
Content-Type 标头的值
实体的全部内容 -这是什么意思?
我想从苹果文档中提供的 json 文件中发布一篇测试文章。
这是生成 auth 标头的类:
public class Security
{
public static string AuthHeader(string method, string url, object content=null)
{
string formDataBoundary = String.Format("{0:N}", Guid.NewGuid());
var apiKeyId = Constants.AppleNewsKeyId;
var apiKeySecret = Constants.AppleNewsKeySecret;
if (string.IsNullOrEmpty(apiKeyId) || string.IsNullOrEmpty(apiKeySecret)) return string.Empty;
var encoding = new ASCIIEncoding();
var dt = DateTime.Now.ToString(Constants.DateFormat);
var canonicalRequest = string.Format("{0}{1}{2}{3}", method, url, dt, content);
var key = Convert.FromBase64String(apiKeySecret);
var hmac = new HMACSHA256(key);
var hashed = hmac.ComputeHash(encoding.GetBytes(canonicalRequest));
var signature = Convert.ToBase64String(hashed);
var authorizaton = string.Format(@"HHMAC; key={0}; signature={1}; date={2}", apiKeyId, signature, dt);
return authorizaton;
}
}
这是常量类:
public static class Constants
{
public static readonly string ChannelId = "myID";
public static readonly string AppleNewsBaseUri = "https://news-api.apple.com";
public static readonly string DateFormat = "yyyy-MM-ddTHH:mm:ssK";
public static readonly string AppleNewsKeySecret = "myID";
public static readonly string AppleNewsKeyId = "myID";
}
以及缺少代码的操作类,以便将正确的内容而不是 null 传递给 AuthHeader 方法:
public class Action
{
public static string SendCommand(string action, string method)
{
var url = $"{Constants.AppleNewsBaseUri}{action}" + "/articles";
//string content = String.Format("{0}:{1}", "Content-Disposition", "form-data; filename=article.json; name=article.json;");
var authheader = Security.AuthHeader(method, url, null);
var request = WebRequest.Create(url);
request.PreAuthenticate = true;
request.Method = "POST";
request.Headers.Add("Authorization", authheader);
if (method.Equals("post", StringComparison.InvariantCultureIgnoreCase))
request.ContentType = "multipart/form-data;" ;
var output = string.Empty;
try
{
string filePath = Path.GetFullPath("article.json");
using (StreamReader r = new StreamReader(filePath))
{
string json = r.ReadToEnd();
dynamic jsonObj = JsonConvert.DeserializeObject(json);
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(json);
request.ContentLength = bytes.Length;
Stream newStream = request.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
}
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
try
{
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
output = reader.ReadToEnd();
}
}
catch (WebException e)
{
using (var reader = new StreamReader(e.Response.GetResponseStream()))
{
output = reader.ReadToEnd();
}
}
return output;
}
public static string ReadChannel()
{
var action = $"/channels/{Constants.ChannelId}";
const string method = "POST";
return SendCommand(action, method);
}
}