Java中处理SOAP API返回的application/octet-stream格式PDF附件的问题
Java中处理SOAP API返回的application/octet-stream格式PDF附件的问题
看起来你踩了一个很常见的坑——把二进制的PDF数据当成普通字符串来处理,这直接破坏了原始的字节信息,导致生成的Base64还原不出正确的PDF。我来给你梳理下问题所在,以及正确的处理方式:
问题根源
你当前的代码把整个响应流用BufferedReader以UTF-8编码读取成字符串,这对二进制数据(比如PDF)是致命的:
- UTF-8是字符编码,专门用于处理文本数据,非字符的二进制字节(比如PDF里的压缩流)会被UTF-8解析器转换成替换字符
�,完全丢失原始字节信息。 - 之后你从这个损坏的字符串里截取PDF内容,再转Base64,自然无法还原出正确的PDF文件。
正确的处理思路
SOAP API返回的是MIME多部分(multipart)响应,包含XML主体和二进制PDF附件两部分。处理这种响应的正确方式是:
- 直接操作原始的
InputStream,不要转成字符串。 - 使用成熟的MIME解析库(比如JavaMail的
MimeMultipart)来拆分响应中的各个部分。 - 定位到
application/octet-stream类型的附件部分,读取其原始二进制字节,再转Base64或直接保存文件。
具体代码修改
1. 依赖准备(Maven)
首先需要引入JavaMail库来解析MIME多部分内容:
<dependency> <groupId>javax.mail</groupId> <artifactId>javax.mail-api</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency>
2. 替换响应处理逻辑
把你代码中从// Get response from the server开始的部分,替换成以下代码:
// 获取响应的Content-Type头(包含MIME边界信息,必须用来解析多部分内容) String contentType = connection.getHeaderField("Content-Type"); // 直接获取原始响应流,不要转成字符串 InputStream responseStream = responseCode >= 200 && responseCode < 300 ? connection.getInputStream() : connection.getErrorStream(); String base64EncodedAttachment = null; try { // 用JavaMail解析MIME多部分响应 ByteArrayDataSource dataSource = new ByteArrayDataSource(responseStream, contentType); MimeMultipart mimeMultipart = new MimeMultipart(dataSource); // 遍历所有MIME部分,找到PDF附件 for (int i = 0; i < mimeMultipart.getCount(); i++) { BodyPart bodyPart = mimeMultipart.getBodyPart(i); String partContentType = bodyPart.getContentType(); String partContentId = bodyPart.getContentID(); // 可以通过Content-Type或Content-ID定位附件(根据你的响应,Content-ID是http://tempuri.org/1/638744554073071663) boolean isPdfAttachment = partContentType.contains("application/octet-stream") || (partContentId != null && partContentId.contains("1/638744554073071663")); if (isPdfAttachment) { // 读取原始二进制PDF数据 InputStream pdfStream = bodyPart.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = pdfStream.read(buffer)) != -1) { baos.write(buffer, 0, bytesRead); } byte[] pdfBytes = baos.toByteArray(); // 直接将原始二进制转Base64 base64EncodedAttachment = Base64.getEncoder().encodeToString(pdfBytes); logger.info("成功提取并编码PDF附件"); break; } } } catch (MessagingException | IOException e) { logger.error("解析MIME响应失败", e); } finally { if (responseStream != null) { responseStream.close(); } }
3. 移除错误的字符串处理代码
删除你原来的getpdfDataEncoded方法,因为它的处理逻辑从根源上就是错误的,不需要再使用。
额外提示
- 如果你不想引入JavaMail依赖,也可以手动解析MIME多部分响应,但需要自己处理边界拆分、头部解析等逻辑,非常容易出错,不推荐。
- 永远记住:二进制数据(图片、PDF、压缩包等)必须直接用
InputStream/OutputStream处理,绝对不能转成String再操作,否则必然损坏数据。
备注:内容来源于stack exchange,提问作者Sourav Sharma
相关产品推荐
相关产品推荐

