从SOAP响应提取二进制转Base64时文件不完整问题排查
WSO2 Integration Studio 8.1.0 提取MTOM SOAP响应完整二进制数据转Base64问题
问题场景
在WSO2 Integration Studio 8.1.0中,尝试从MTOM格式的SOAP响应提取二进制数据并转换为Base64字符串,但仅能获取部分数据。SOAP响应包含xop:Include引用的二进制附件,文件总大小4586622字节,缓冲大小1048576字节。使用以下两种方式均得到不完整或损坏的Base64字符串:
<property expression="$body/fn:GetContentResponse/fn:ContentResponse/fn:Content/fn:Binary" name="DataBase64" scope="default" type="STRING" xmlns:fn="http://www.filenet.com/ns/fnce/2006/11/ws/schema"/>
<property expression="base64Encode($body/fn:GetContentResponse/fn:ContentResponse/fn:Content/fn:Binary)" name="DataBase64" scope="default" type="STRING" xmlns:fn="http://www.filenet.com/ns/fnce/2006/11/ws/schema"/>
问题原因
- MTOM解析未启用:默认情况下Synapse未自动解析MTOM格式的
xop:Include引用,直接提取Binary节点只能拿到引用标识,而非实际二进制内容。 - 分块响应未处理:SOAP响应的
continueFrom参数(offset=1048576;id={...})表明服务采用分块返回策略,当前仅获取了第一块(1048576字节)数据,未循环请求剩余部分。
解决步骤
1. 启用MTOM解析
在序列中添加属性开启MTOM支持,让Synapse自动解析xop:Include并加载附件内容:
<property name="enableMTOM" value="true" scope="axis2"/>
2. 处理分块响应,循环获取完整数据
通过while mediator循环调用服务,直到continueFrom为空,拼接每次返回的二进制数据后再转换为Base64。修改后的核心逻辑如下:
<!-- 初始化存储完整二进制数据的属性 --> <property name="FullBinaryData" scope="default" type="OM"/> <property name="ContinueToken" expression="$body/fn:GetContentResponse/fn:ContentResponse/@continueFrom" scope="default" type="STRING" xmlns:fn="http://www.filenet.com/ns/fnce/2006/11/ws/schema"/> <!-- 循环获取分块数据 --> <while xmlns:fn="http://www.filenet.com/ns/fnce/2006/11/ws/schema" expression="boolean(get-property('ContinueToken')) != ''"> <sequence> <!-- 构建带continueFrom参数的请求 --> <payloadFactory media-type="xml"> <format> <soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header> <Security xmlns="http://schemas.xmlsoap.org/ws/2002/12/secext"> <hd:UsernameToken xmlns:hd="http://schemas.xmlsoap.org/ws/2002/12/secext"> <hd:Username>$1</hd:Username> <hd:Password>$2</hd:Password> </hd:UsernameToken> </Security> </soapenv:Header> <soapenv:Body> <p857:GetContentRequest validateOnly="0" xmlns:p857="http://www.filenet.com/ns/fnce/2006/11/ws/schema"> <p857:ContentRequest continueFrom="$6" cacheAllowed="1" id="1" startOffset="0"> <p857:SourceSpecification classId="$4" itemIndex="0" objectId="$5" objectStore="$3" serializationDuplicate="0" xsi:type="p857:ObjectSpecification"/> <p857:ElementSpecification elementSequenceNumber="0" itemIndex="0"/> </p857:ContentRequest> </p857:GetContentRequest> </soapenv:Body> </soapenv:Envelope> </format> <args> <arg evaluator="xml" expression="get-property('Username')"/> <arg evaluator="xml" expression="get-property('Password')"/> <arg evaluator="xml" expression="get-property('ObjectStore')"/> <arg evaluator="xml" expression="get-property('DocumentClass')"/> <arg evaluator="xml" expression="get-property('DocumentId')"/> <arg evaluator="xml" expression="get-property('ContinueToken')"/> </args> </payloadFactory> <call-template target="StorageEndpointTemplate"/> <!-- 提取当前块的二进制数据并拼接到完整数据中 --> <property name="CurrentBinary" expression="$body/fn:GetContentResponse/fn:ContentResponse/fn:Content/fn:Binary" scope="default" type="OM"/> <script language="js"><![CDATA[ var fullData = mc.getProperty('FullBinaryData'); var currentData = mc.getProperty('CurrentBinary'); if (fullData == null) { fullData = currentData; } else { fullData.appendChild(currentData.getFirstOMChild()); } mc.setProperty('FullBinaryData', fullData); ]]></script> <!-- 更新continueToken,若为空则退出循环 --> <property name="ContinueToken" expression="$body/fn:GetContentResponse/fn:ContentResponse/@continueFrom" scope="default" type="STRING"/> </sequence> </while> <!-- 将完整二进制数据转换为Base64 --> <property expression="base64Encode(get-property('FullBinaryData'))" name="DataBase64" scope="default" type="STRING"/>
3. 注意事项
- 处理大文件时需关注内存占用,避免内存溢出;若文件过大,建议采用流处理而非全量加载到内存。
- 需确保后端服务支持分块续传逻辑,
continueFrom参数格式需与服务要求一致。
内容的提问来源于stack exchange,提问作者Mahmoud Saleh
相关产品推荐
相关产品推荐

