c# - 如何在 C# [Open Invoice] 中发布具有两种不同文档类型和 HMAC 签名的 Multipart/mixed:boundary=”MIME-Boundary”
问题描述
作为与 Open Invoice 集成的一部分,API 需要传统的 Multipart/mixed:boundary=”MIME-Boundary” 请求标头。在 Internet 上使用此 C# Header 的文档非常少,包括 Microsoft 文档。
POST 请求中的两个文档包括一个 UTF-8 XML 字符串和一个 Base64 pdf 字符串。出站请求需要 HTTPRequestMessage 本身不支持的 Content-Type 标头(每个文档一个),因为它假定您将交付“文本/纯文本”请求。
Headers.Add() //设置Content-Type时抛出异常
Headers.TryAddWithoutValidation() //没有解决问题
此外,请求需要使用请求正文的 HMAC 哈希进行签名。
如何在 C# 中构建此请求?
解决方案
构建客户端
X509Certificate2 cert = new X509Certificate2(certificateName, certPassword);
var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(cert);
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(openInvoiceURL);
构建请求
//Starting from byte[] for both files
var xmlString = System.Text.Encoding.UTF8.GetString(xmlBytes);
string pdf64 = Convert.ToBase64String(pdfBytes);
string url = "/docp/supply-chain/v1/invoices";
var multiPartContent = new MultipartContent("mixed", "_MIME-Boundary");
var xmlHttpContent = new StringContent(xmlString);
xmlHttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
multiPartContent.Add(xmlHttpContent);
var pdfHttpContent = new StringContent(pdf64);
pdfHttpContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
pdfHttpContent.Headers.Add("content-transfer-encoding", "base64");
pdfHttpContent.Headers.Add("Content-ID", pdfName);
multiPartContent.Add(pdfHttpContent);
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Content = multiPartContent;
request = AttachHMAC(request, secretKey);
var response = client.SendAsync(request).Result;
var responseString = response.Content.ReadAsStringAsync().Result;
签署请求正文(仅在 POST 上)
private HttpRequestMessage AttachHMAC(HttpRequestMessage request, string secretKey)
{
var payload = string.Empty;
if(request != null && request.Content != null)
{
payload = request.Content.ReadAsStringAsync().Result;
}
var hashMaker = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
var payloadByteArray = Encoding.UTF8.GetBytes(payload);
byte[] hash = hashMaker.ComputeHash(payloadByteArray);
var base64Hash = Convert.ToBase64String(hash);
request.Headers.Add("mac", base64Hash);
return request;
}
推荐阅读
- python - 为什么 read_csv 或 read_excel 不将 'r' 用作原始字符串文字?
- java - OnBackPress 在 android 中的行为不同
- android - 改造中的 onResponse 出错
- c++ - 执行“make”时出现 QT 错误
- javascript - 通过 HTML 表单访问 PHP 文件
- python - 生成一个视图以识别python中列中特定值的第一个条目和最后一个条目
- android - strings.xml:错误:多次找到项目字符串/按钮
- python - I.Gertsbakh 的书“可靠性理论:预防性维护的应用?”第 7.3 节的模拟
- android - 如何在当前时间添加分钟并从当前时间中减去它以运行计时器?
- vue.js - 如何在元素 UI 中的子 Select Dropdown 的 @change 事件上获取选定的行索引?