如何在C#中从SOAP响应提取PDF附件到本地文件夹?
问题根源
- 误用
ZipArchive处理gzip压缩流:gzip是单文件压缩格式,并非多文件zip归档,用ZipArchive解析会触发「不支持的压缩方法」异常 - 未正确拆分multipart/related响应:需要先按响应头里的边界分割内容,定位到包含PDF的gzip压缩块
修正后的完整代码
using System; using System.IO; using System.IO.Compression; using System.Net.Http; using System.Text; public class SoapPdfExtractor { public async System.Threading.Tasks.Task ExtractPdfFromSoapResponse(HttpResponseMessage response) { // 1. 从响应头获取multipart边界 var contentType = response.Content.Headers.ContentType; var boundary = contentType.Parameters.Find(p => p.Name.Equals("boundary", StringComparison.OrdinalIgnoreCase))?.Value; if (string.IsNullOrEmpty(boundary)) throw new InvalidOperationException("无法获取multipart/related的边界值"); // 2. 读取完整响应内容 var responseContent = await response.Content.ReadAsStringAsync(); var boundaryDelimiter = $"--{boundary}"; // 3. 拆分multipart块,定位到gzip压缩的PDF部分 var parts = responseContent.Split(new[] { boundaryDelimiter }, StringSplitOptions.RemoveEmptyEntries); foreach (var part in parts) { // 检查当前块是否包含gzip压缩的PDF(根据Content-Type判断) if (part.Contains("Content-Type: application/x-gzip") || part.Contains("Content-Encoding: gzip")) { // 提取块中的二进制内容(跳过头部,找到空行后的内容) var contentStartIndex = part.IndexOf("\r\n\r\n", StringComparison.Ordinal) + 4; if (contentStartIndex >= part.Length) continue; var gzipBytes = Encoding.ASCII.GetBytes(part.Substring(contentStartIndex)); // 4. 用GZipStream解压gzip流 using var gzipStream = new GZipStream(new MemoryStream(gzipBytes), CompressionMode.Decompress); using var pdfStream = new MemoryStream(); await gzipStream.CopyToAsync(pdfStream); // 5. 保存PDF到下载文件夹 var downloadPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "extracted.pdf"); await File.WriteAllBytesAsync(downloadPath, pdfStream.ToArray()); Console.WriteLine($"PDF已保存至: {downloadPath}"); break; } } } }
关键细节说明
- 边界解析:从
Content-Type头的boundary参数获取分割符,确保正确拆分multipart块 - 内容定位:每个multipart块包含头部和内容,通过空行(
\r\n\r\n)分割头部与二进制内容,避免把HTTP头混入压缩流 - gzip解压:使用
GZipStream处理单文件gzip压缩,这是gzip格式的正确处理方式,不要用ZipArchive - 路径处理:使用
Environment.SpecialFolder.UserProfile获取系统下载文件夹路径,保证跨平台兼容性
内容的提问来源于stack exchange,提问作者JohnB
相关产品推荐
相关产品推荐

