C#如何构造适配Open Invoice、带双类型文档与HMAC签名的Multipart/mixed请求
C#构造符合Open Invoice要求的Multipart/mixed请求方案
针对legacy格式的Multipart/mixed请求、单部分独立设置Content-Type、自定义固定boundary的需求,可以通过手动配置MultipartContent对象、分类设置内容头的方式实现,无需自行拼接整个请求体,可兼容接口格式要求。
具体实现步骤
引入必要命名空间
实现过程需要用到以下系统命名空间:using System.Net.Http; using System.Net.Http.Headers; using System.Security.Cryptography; using System.Text;构造指定boundary的MultipartContent对象
按接口要求固定boundary值,同时兼容legacy格式不自动包裹引号:// 按接口要求指定固定boundary值 const string Boundary = "MIME-Boundary"; // 构造multipart/mixed类型的内容容器 var multipartContent = new MultipartContent("mixed", Boundary); // 移除系统默认给boundary加的双引号,适配legacy接口要求 multipartContent.Headers.ContentType.Parameters.First(p => p.Name == "boundary").Value = Boundary;分别添加两份文档内容,独立配置每个部分的Content-Type
每个文档单独构造内容对象,单独指定Content-Type,不会被默认覆盖为text/plain:// 1. 添加UTF-8格式的XML部分 string xmlStr = "你的业务XML字符串内容"; var xmlPart = new StringContent(xmlStr, Encoding.UTF8); // 按接口要求设置XML部分的Content-Type xmlPart.Headers.ContentType = MediaTypeHeaderValue.Parse("application/xml; charset=utf-8"); multipartContent.Add(xmlPart); // 2. 添加Base64编码的PDF部分 string base64PdfStr = "你的Base64编码后的PDF内容"; var pdfPart = new StringContent(base64PdfStr, Encoding.UTF8); // 按接口要求设置PDF部分的Content-Type pdfPart.Headers.ContentType = MediaTypeHeaderValue.Parse("application/pdf; charset=utf-8"); multipartContent.Add(pdfPart);生成HMAC签名,构造最终请求
先读取完整请求体字节流计算签名,再构造请求消息配置校验头:// 读取完整请求体字节流用于签名计算 byte[] requestBodyBytes = await multipartContent.ReadAsByteArrayAsync(); // 生成HMAC签名,哈希算法、密钥、签名格式按接口实际要求调整,以下为SHA256示例 string hmacSecret = "你的接口签名密钥"; string hmacSign; using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(hmacSecret))) { byte[] hashBytes = hmac.ComputeHash(requestBodyBytes); hmacSign = Convert.ToBase64String(hashBytes); } // 构造最终请求对象 var request = new HttpRequestMessage(HttpMethod.Post, "你的Open Invoice接口地址"); request.Content = multipartContent; // 添加签名头,头名按接口实际要求替换 request.Headers.TryAddWithoutValidation("X-HMAC-Signature", hmacSign);发送请求
注意HttpClient最好全局实例化复用,不要每次请求新建实例避免端口耗尽问题// 示例HttpClient为局部变量,生产环境建议替换为全局单例 using var client = new HttpClient(); var response = await client.SendAsync(request); // 处理返回结果 response.EnsureSuccessStatusCode(); string responseResult = await response.Content.ReadAsStringAsync();
常见问题规避
- Content-Type属于内容头,不要直接添加到HttpRequestMessage.Headers中,否则会抛出无效头异常,需要设置在request.Content.Headers下
- 如果接口要求boundary必须用双引号包裹,将构造MultipartContent时的boundary值改为
"\"MIME-Boundary\""即可 - HMAC签名计算必须在整个MultipartContent构造完成之后执行,避免内容修改导致签名校验不通过
内容的提问来源于stack exchange,提问作者Shane
相关产品推荐
相关产品推荐

