查找来自 Salesforce Connector Mule 4 的响应的 contentLength

Finding the contentLength for response from Salesforce Connector Mule 4

我一直在开发 mule 应用程序 (4.4.0),它调用 salesforce 查询连接器并将来自 SF 连接器的响应转换为 CSV,然后通过创建对象连接器将 CSV 上传到 AWS s3。

我收到如下错误:“com.amazonaws.SdkClientException:读取的数据长度与预期长度不同”

我的代码配置如下所示:-

        <salesforce:query doc:name="sobject from salesforce" doc:id="58660352-f117-47e3-91cf-587f5000d591" config-ref="salesforceConfig" >
                    <salesforce:salesforce-query >#[vars.query]</salesforce:salesforce-query>
                    </salesforce:query>
                    
    <ee:transform doc:name="convert to csv" doc:id="ed22a2df-82a6-4162-9c3d-eab29dc92a4f">
                    <ee:message>
                        <ee:set-payload><![CDATA[%dw 2.0
        output application/csv quoteHeader=true, quoteValues=true
        ---
        payload]]></ee:set-payload>
                    </ee:message>
                </ee:transform>

<ee:transform doc:name="Transform Message" doc:id="62f61426-f0df-4640-bb27-4a980a4f26fa" >
            <ee:message >
            </ee:message>
            <ee:variables >
                <ee:set-variable variableName="contentLength" ><![CDATA[%dw 2.0
output application/java
---
sizeOf(write(payload, "application/java"))]]></ee:set-variable>
            </ee:variables>
        </ee:transform>
    
    <s3:create-object doc:name="Create object" doc:id="136d5816-846c-4e52-acb6-0caeacb25dba" config-ref="Amazon_S3_Configuration" bucketName="#[vars.s3BucketName]" key='#[(if(!isEmpty(vars.s3WriteKey)) vars.s3WriteKey ++ "/" else "") ++ vars.fileNameOnS3]' contentLength="#[vars.contentLength]"/>

它正在创建如下异常:-

com.amazonaws.SdkClientException: More data read than expected: dataLength=1048; expectedLength=7; includeSkipped=false; in.getClass()=class com.amazonaws.internal.ReleasableInputStream; markedSupported=false; marked=0; resetSinceLastMarked=false; markCount=0; resetCount=0

我可以看出此错误是由于我根据负载大小计算的 contentLength 不匹配所致。我尝试了各种选项,如 sizeOf(payload) 、 sizeOf(write(payload)) 等。都是一样的错误。

非常感谢任何帮助。非常感谢

简短版本:

选择两者之一:

  1. 不要传递 contentLength 参数,除非某些用例需要它,因为它是自动处理的。
  2. 如果出于某种原因,您必须传递 contentLength,您应该使用 write(payload, 'application/csv', {quoteHeader: true, quoteValues: true}) 将有效负载写为字符串。然后,您可以使用 sizeOf(payload) 或内容长度元数据选择器 payload.^contentLength 获取有效负载的大小(在稍后使用之前,请阅读第 3 点 长版)

长版:

在计算 CSV 的大小时,您将有效负载写为 application/java,这会将您的 CSV 写入 Java ArrayList,然后计算该字符串的大小。

现在你会认为把application/java改成application/csv就能解决问题,其实不然。如果你查看 write 函数的文档,你会发现它接受名为 writerProperties 的第三个参数,在你的情况下,它是 {quoteHeader: true, quoteValues: true} (这些是您在创建有效载荷时使用的)。由于这些属性不是默认属性,如果您未在写入函数 中指定这些属性,您将从 write 函数获得与您的负载 不同的输出。

你应该做什么?

  1. 我会先看看我是否真的需要自己传递 contentLength?据我所知,它会自动处理。
  2. 如果你真的需要通过 contentLength,你应该先把你的 payload 转换成 CSV 格式后写成你想要的格式,像下面这样
%dw 2.0
output text/plain
---
write (payload, "application/csv", {quoteHeader: true, quoteValues: true})

然后就可以使用sizeOf(payload)了。您不应在计算大小时修改有效负载,因为正如您刚才所经历的那样,该修改可能会改变长度。

  1. 需要测试:。由于您使用的是 application/csv 内容类型,因此您可以直接使用 Content Length Metadata Selector 获取 contentLength。即 payload.^contentLength。但是,我是说它需要测试,因为这个元数据选择器有时 returns null,例如,当 payload 输出类型为 application/java 时。我 99% 确定使用 csv 您将始终获得内容类型元数据,但不是 100%,因为我不知道为什么有时在其他 MIME 类型中没有填充它。如果您选择使用它,您的 s3 连接器将如下所示
<s3:create-object doc:name="Create object"
                  doc:id="136d5816-846c-4e52-acb6-0caeacb25dba"
                  config-ref="Amazon_S3_Configuration"
                  bucketName="#[vars.s3BucketName]"
                  key='#[(if(!isEmpty(vars.s3WriteKey)) vars.s3WriteKey ++ "/" else "") ++ vars.fileNameOnS3]'
                  contentLength="#[payload.^contentLength]"/>