WSO2 Iterator Mediator内VFS传输错误排查与修复咨询
修复VFS传输错误:Iterator Mediator流程终止问题
问题描述
我正在将CSV文件转换为JSON格式,通过Iterator Mediator结合Payload-Factory Mediator修改每条JSON数据后发送至指定端点,但最终出现VFS传输错误。迭代器mediator之前的日志均正常打印,流程在迭代器处终止并抛出错误。
错误日志
ERROR {VFSTransportSender} - Error while attaching VFS file system properties. null [2022-07-20 19:30:46,925] ERROR {VFSTransportSender} - Unable to determine out transport information to send message [2022-07-20 19:30:46,929] ERROR {Axis2Sender} - {proxy:TestProxy} Access-Control-Allow-Credentials:true,Access-Control-Allow-Headers:Authorization, Content-Type, fluent.account,Access-Control-Allow-Methods:POST, PUT, GET, OPTIONS, DELETE,Access-Control-Allow-Origin:*,Access-Control-Expose-Headers:flex.type, flex.version,Access-Control-Max-Age:3600,Cache-Control:no-cache, no-store, max-age=0, must-revalidate,Connection:keep-alive,Content-Type:application/json;charset=UTF-8,Date:Wed, 20 Jul 2022 14:00:47 GMT,Expires:0,Pragma:no-cache,Server:nginx/1.10.3 (Ubuntu),Transfer-Encoding:chunked,X-Content-Type-Options:nosniff,X-Frame-Options:DENY,X-XSS-Protection:1; mode=block, Unexpected error sending message back org.apache.axis2.AxisFault: Unable to determine out transport information to send message at org.apache.axis2.transport.base.AbstractTransportSender.handleException(AbstractTransportSender.java:234) at org.apache.synapse.transport.vfs.VFSTransportSender.writeFile(VFSTransportSender.java:331) at org.apache.synapse.transport.vfs.VFSTransportSender.sendMessage(VFSTransportSender.java:189) at org.apache.axis2.transport.base.AbstractTransportSender.invoke(AbstractTransportSender.java:119) at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:442) at org.apache.synapse.core.axis2.Axis2Sender.sendBack(Axis2Sender.java:213) at org.apache.synapse.mediators.builtin.RespondMediator.mediate(RespondMediator.java:46) at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:109) at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:263) at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.mediateFromContinuationStateStack(Axis2SynapseEnvironment.java:820) at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:322) at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:608) at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:207) at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180) at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:298) at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)
原Synapse配置
<?xml version="1.0" encoding="UTF-8"?> <proxy name="TestProxy" startOnLoad="true" transports="http https vfs" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <smooks config-key="smooks_conf"> <input type="text"/> <output type="xml"/> </smooks> <log level="full"/> <property name="messageType" scope="axis2" type="STRING" value="application/json"/> <log> <property expression="json-eval($)" name="Response"/> </log> <call-template target="Template"/> <log> <property name="Info" value="Before Iteration"/> </log> <iterate continueParent="true" expression="$body//ProductData/Product" id="Iterate-over-products" xmlns:ns="http://org.apache.synapse/xsd"> <target> <sequence> <log> <property name="Info" value="Inside Iteration"/> </log> <payloadFactory media-type="json"> <format>
 {
 "ref": "$1",
 "name": "$2",
 "summary": "This is a HP",
 "attributes": [
 {
 "name": "imageUrl",
 "type": "STRING",
 "value": "$3"
 },
 ]
 }
 }
 </format> <args> <arg evaluator="json" expression="$.Product.ProductCode" /> <arg evaluator="json" expression="$.Product.ProductName" /> <arg evaluator="json" expression="$.Product.ProductUrl"/> </args> </payloadFactory> <property name="messageType" scope="axis2" type="STRING" value="application/json"/> <call> <endpoint> <http method="post" uri-template""=> <suspendOnFailure> <initialDuration>-1</initialDuration> <progressionFactor>-1</progressionFactor> <maximumDuration>0</maximumDuration> </suspendOnFailure> <markForSuspension> <retriesBeforeSuspension>0</retriesBeforeSuspension> </markForSuspension> </http> </endpoint> </call> <log> <property expression="json-eval($)" name="product"/> </log> </sequence> </target> </iterate> <respond/> </inSequence> <outSequence/> <faultSequence/> </target> <parameter name="transport.vfs.Streaming">true</parameter> <parameter name="transport.PollInterval">1</parameter> <parameter name="transport.vfs.FileURI">file://C://in</parameter> <parameter name="transport.vfs.ContentType">text/plain</parameter> <parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter> <parameter name="transport.vfs.MoveAfterFailure">file://C:/out</parameter> <parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter> <parameter name="transport.vfs.FileNamePattern">.*.csv</parameter> <parameter name="transport.vfs.MoveAfterProcess">file://C:/history</parameter> </proxy>
错误原因分析
- Respond Mediator误用:VFS代理是单向轮询处理模式,无需向VFS传输通道返回响应,但配置中的
<respond/>会强制尝试发送响应,而VFS没有对应的输出传输信息,导致核心错误。 - Call Mediator端点配置错误:
<http method="post" uri-template""=>存在语法错误,uri-template属性值为空且格式错误,无法正确定位目标端点。 - Payload Factory JSON格式错误:Format部分末尾多了一个多余的
},导致生成的JSON结构无效。 - Iterator的continueParent设置冲突:
continueParent="true"会让父消息继续执行后续的<respond/>,干扰子流程的正常执行。
修复步骤
1. 移除Respond Mediator
删除<inSequence>末尾的<respond/>,VFS代理不需要向文件系统返回响应。
2. 修复Call Mediator的端点配置
填写正确的目标端点URL,修正uri-template的语法错误,例如:
<http method="post" uri-template="http://your-target-api-endpoint/products"/>
3. 修正Payload Factory的JSON格式
删除Format部分最后多余的},同时移除attributes数组中多余的逗号,修正后的Format如下:
<format>
 {
 "ref": "$1",
 "name": "$2",
 "summary": "This is a HP",
 "attributes": [
 {
 "name": "imageUrl",
 "type": "STRING",
 "value": "$3"
 }
 ]
 }
 </format>
4. 调整Iterator的continueParent设置(可选)
如果不需要保留父消息后续处理,将continueParent="true"改为continueParent="false",确保父流程不会干扰子流程的执行。
修正后的完整配置示例
<?xml version="1.0" encoding="UTF-8"?> <proxy name="TestProxy" startOnLoad="true" transports="http https vfs" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <smooks config-key="smooks_conf"> <input type="text"/> <output type="xml"/> </smooks> <log level="full"/> <property name="messageType" scope="axis2" type="STRING" value="application/json"/> <log> <property expression="json-eval($)" name="Response"/> </log> <call-template target="Template"/> <log> <property name="Info" value="Before Iteration"/> </log> <iterate continueParent="false" expression="$body//ProductData/Product" id="Iterate-over-products" xmlns:ns="http://org.apache.synapse/xsd"> <target> <sequence> <log> <property name="Info" value="Inside Iteration"/> </log> <payloadFactory media-type="json"> <format>
 {
 "ref": "$1",
 "name": "$2",
 "summary": "This is a HP",
 "attributes": [
 {
 "name": "imageUrl",
 "type": "STRING",
 "value": "$3"
 }
 ]
 }
 </format> <args> <arg evaluator="json" expression="$.Product.ProductCode" /> <arg evaluator="json" expression="$.Product.ProductName" /> <arg evaluator="json" expression="$.Product.ProductUrl"/> </args> </payloadFactory> <property name="messageType" scope="axis2" type="STRING" value="application/json"/> <call> <endpoint> <http method="post" uri-template="http://your-target-api-endpoint/products"> <suspendOnFailure> <initialDuration>-1</initialDuration> <progressionFactor>-1</progressionFactor> <maximumDuration>0</maximumDuration> </suspendOnFailure> <markForSuspension> <retriesBeforeSuspension>0</retriesBeforeSuspension> </markForSuspension> </http> </endpoint> </call> <log> <property expression="json-eval($)" name="product"/> </log> </sequence> </target> </iterate> </inSequence> <outSequence/> <faultSequence/> </target> <parameter name="transport.vfs.Streaming">true</parameter> <parameter name="transport.PollInterval">1</parameter> <parameter name="transport.vfs.FileURI">file://C://in</parameter> <parameter name="transport.vfs.ContentType">text/plain</parameter> <parameter name="transport.vfs.ActionAfterProcess">MOVE</parameter> <parameter name="transport.vfs.MoveAfterFailure">file://C:/out</parameter> <parameter name="transport.vfs.ActionAfterFailure">MOVE</parameter> <parameter name="transport.vfs.FileNamePattern">.*.csv</parameter> <parameter name="transport.vfs.MoveAfterProcess">file://C:/history</parameter> </proxy>
内容的提问来源于stack exchange,提问作者Ruby
相关产品推荐
相关产品推荐

