C# .NET 4.8 POST API改请求体传参 解决415问题打开PDF
核心问题排查
- 项目基于.NET Framework 4.8 开发,原有逻辑通过GET查询串传参调用第三方接口获取PDF,可正常在浏览器打开、保存文件
- 第三方接口更新规则:要求请求参数必须放在POST请求体中,不再支持查询串传参
- 改造过程中先后遇到两类故障:
- 调用接口持续返回415 Unsupported Media Type错误
- 可正常拿到响应后,生成的PDF保存到本地重新打开时提示编码格式不匹配,无法正常加载
常见错误写法与问题根源
触发415错误的错误代码
string QS1 = "A=this&B=is&c=EasyOnceYouGetTheRightAnswer"; Uri URI = new Uri("https://Mypost.com/RequestMyPDF"); using (WebClient wc = new WebClient()) { // 以下写法均触发415错误 //Byte[] buffer = wc.UploadData(URI, "POST", System.Text.Encoding.ASCII.GetBytes(QS1)); //Byte[] buffer = wc.UploadData(URI, "POST", System.Text.Encoding.UTF8.GetBytes(QS1)); Byte[] buffer = wc.UploadData(URI, "POST",System.Text.Encoding.UTF8.GetBytes(QS1)); }
问题根源:未匹配第三方接口要求的请求Content-Type,直接上传原始字符串字节流时,没有声明对应的媒体类型。从原有GET查询串格式推断,接口要求接收的是
application/x-www-form-urlencoded格式的POST表单,之前尝试的application/xml、text/plain、无媒体类型声明的裸字节流,都会被服务端判定为无效请求直接返回415。
生成损坏PDF的错误写法
System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()); StreamWriter objSW = new StreamWriter(@"c:\temp\Destination123.PDF", false, Encoding.Default); objSW.Write(sr.ReadToEnd().Trim()); objSW.Close();
问题根源:PDF是纯二进制格式文件,不能用面向文本的StreamReader、StreamWriter做读写转换。这类类会自动按编码规则篡改原始二进制字节流,最终生成的PDF文件为空、格式完全损坏,打开时自然会提示编码不匹配。
另外之前代码输出PDF时没有调用Response.Clear(),页面之前的输出残留会混入PDF字节流,导致文件头损坏,也是PDF格式异常的常见原因。
可正常运行的实现方案
核心实现要点:
- 用WebClient内置的
UploadValues方法自动按标准表单格式编码参数,不需要手动拼接查询字符串、手动转字节 - 明确声明请求的Content-Type为
application/x-www-form-urlencoded,解决415错误 - 输出响应时先清理残留输出,全程用二进制流写入,不做任何文本编码转换
// 构造与原GET查询串等价的表单参数字典 var formParameters = new System.Collections.Specialized.NameValueCollection() { {"A", "this"}, {"B", "is"}, {"C", "EasyOnceYouGetTheRightAnswer"} }; string apiUrl = "https://Mypost.com/RequestMyPDF"; byte[] pdfBytes; using (var wc = new System.Net.WebClient()) { // 声明正确的请求媒体类型 wc.Headers.Add(System.Net.HttpRequestHeader.ContentType, "application/x-www-form-urlencoded"); // 自动编码表单参数后发送POST请求 pdfBytes = wc.UploadValues(apiUrl, "POST", formParameters); } if (pdfBytes != null && pdfBytes.Length > 0) { // 清理之前的页面输出残留,避免混入PDF字节流 Response.Clear(); Response.ContentType = "application/pdf"; Response.AddHeader("Content-Length", pdfBytes.Length.ToString()); // 可选:设置内联打开/下载的响应头 // Response.AddHeader("Content-Disposition", "inline; filename=export.pdf"); Response.BinaryWrite(pdfBytes); Response.End(); }
如果需要用WebRequest实现,读取响应时必须直接做二进制流复制,绝对不能用StreamReader做文本转换:
// 正确读取二进制响应流的方式 using (var response = req.GetResponse()) using (var responseStream = response.GetResponseStream()) using (var ms = new System.IO.MemoryStream()) { // 直接把原始字节流复制到内存,不做任何编码转换 responseStream.CopyTo(ms); byte[] pdfBytes = ms.ToArray(); }
内容的提问来源于stack exchange,提问作者Danimal111
相关产品推荐
相关产品推荐

