如何在ColdFusion中读取多部分响应

如何在ColdFusion中读取多部分响应,coldfusion,multipart,mtom,cfhttp,Coldfusion,Multipart,Mtom,Cfhttp,我正在向一个web服务发送一篇CFHTTP帖子,该服务返回两部分(多部分),一部分是XML,另一部分是PDF。我只想得到PDF文件。我的cfhttp.filecontent是java.io.ByteArrayOutputStream类型。当我执行toString()时,我得到以下结果 --MIME_Boundary Content-ID: <aa82dfa.N51ec355b.3.15b86044531.59d6> Content-Type: application/xop+xml;

我正在向一个web服务发送一篇CFHTTP帖子,该服务返回两部分(多部分),一部分是XML,另一部分是PDF。我只想得到PDF文件。我的
cfhttp.filecontent
java.io.ByteArrayOutputStream
类型。当我执行
toString()
时,我得到以下结果

--MIME_Boundary
Content-ID: <aa82dfa.N51ec355b.3.15b86044531.59d6>
Content-Type: application/xop+xml; type="text/xml"; charset=utf-8
Content-Transfer-Encoding: 8bit
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">....</soapenv:Envelope>
--MIME_Boundary
Content-Id: <2958beaa-dd72-4879-9d80-cc19876b2c2a@example.jaxws.sun.com>
Content-Type: application/pdf
Content-Transfer-Encoding: binary

%PDF-1.4
%ÈÁÄ×
<content removed>
25081
%%EOF

--MIME_Boundary--
第一部分

Content-Type: application/xop+xml; type="text/xml"; charset=utf-8
Content-Transfer-Encoding: 8bit
第二部分

Content-Type: application/pdf
Content-Transfer-Encoding: binary
我在cfhttp.fileContent中得到响应,数据如下所示

--MIME_Boundary
Content-ID: <aa82dfa.N51ec355b.3.15b86044531.59d6>
Content-Type: application/xop+xml; type="text/xml"; charset=utf-8
Content-Transfer-Encoding: 8bit
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">....</soapenv:Envelope>
--MIME_Boundary
Content-Id: <2958beaa-dd72-4879-9d80-cc19876b2c2a@example.jaxws.sun.com>
Content-Type: application/pdf
Content-Transfer-Encoding: binary

%PDF-1.4
%ÈÁÄ×
<content removed>
25081
%%EOF

--MIME_Boundary--

当我调用
toByteArray()
时,我得到二进制数据。然后我将数据保存到一个文件中,我看到了文件的XML和PDF部分。

解决方案需要两个更改:将接受的编码值设置为gzip、deflate和使用java处理二进制数据

<cfhttpparam type="HEADER" name="Accept-Encoding" value="gzip,deflate">
接下来,我使用了Ben Nadel的一个实用程序,它包含了我需要的所有二进制操作。我使用方法
binarysicle()
提取二进制文件的开始和结束部分。切片数据包含我所需要的精确格式的二进制文件。它不是base64或任何其他类型,而是二进制的

sliced = binNadel.binarySlice( binResponse, <int posistion to start slice>, <int length of binary>));
sliced=binNadel.binarysicle(binResponse,);
这个解决方案是可行的,但它已经成熟,可能会出现一些问题,例如响应顺序可能会切换,边界名称可能会更改,等等。因此,这将需要大量的错误处理来确保顺利进行

更新:

接下来,我研究了一下,看看是否可以简化我的代码。他们建议使用Java支持的类。以下是最终工作代码:

<cfscript>
    // Modify path as needed
    saveToDirec = "c:\temp\";

    // Hard coded "boundary" value for DEMO purposes. It MUST match actual value used in cfhttp response
    // Best to use cfhttp.responseHeader.content-Type so [if] the service changes your code won't break.
    contentType = "multipart/related; boundary=MIME_Boundary;";  

    // Load and parse ByteArrayOutputStream returned by CFHTTP
    dataSource = createObject("java", "javax.mail.util.ByteArrayDataSource").init(m_strSoapResponse.fileContent.toByteArray(), javaCast( "string", contentType));
    mimeParts = createObject("java", "javax.mail.internet.MimeMultipart").init(dataSource);

    for (i = 0; i < mimeParts.getCount(); i++) {
        writeOutput("<br>Processing part["& i &"]");
        bp = mimeParts.getBodyPart( javacast("int", i));

        // If this part is a PDF, save it to a file.
        if (!isNull(bp) && bp.isMimeType("application/pdf")) {
            outputFile = createObject("java", "java.io.File").init(saveToDirec &"demo_savedfile_"& i &".pdf");
            bp.saveFile(outputFile);
            writeOutput("<br>Saved: "& outputFile.getAbsolutePath());
        }
    }
</cfscript>

//根据需要修改路径
saveToDirec=“c:\temp\”;
//用于演示目的的硬编码“边界”值。它必须与cfhttp响应中使用的实际值匹配
//最好使用cfhttp.responseHeader.content-Type,这样[如果]服务更改,代码就不会中断。
contentType=“多部分/相关;边界=MIME_边界;”;
//加载并解析CFHTTP返回的ByteArrayOutputStream
dataSource=createObject(“java”、“javax.mail.util.ByteArrayDataSource”).init(m_strSoapResponse.fileContent.toByteArray(),javaCast(“string”,contentType));
mimeParts=createObject(“java”,“javax.mail.internet.MimeMultipart”).init(数据源);
对于(i=0;i处理部分[”&i&“]);
bp=mimeParts.getBodyPart(javacast(“int”,i));
//如果此部分是PDF,请将其保存到文件中。
如果(!isNull(bp)和&bp.isMimeType(“应用程序/pdf”)){
outputFile=createObject(“java”、“java.io.File”).init(saveToDirec&“demo\u savedfile”&i&“pdf”);
bp.saveFile(outputFile);
writeOutput(
已保存:&outputFile.getAbsolutePath()); } }

谢谢大家的意见

不要使用
toString()
转换
cfhttp.filecontent
变量,而是尝试转储它。这将向您展示ColdFusion为您创建的保存每一条信息的结构<代码>或在脚本
writeDump(cfhttp.filecontent)中。将该输出复制到上面的问题。一旦我们知道了包含实际二进制数据的字段,您需要在向用户显示之前将base64解码回二进制。类似于
的感谢您的回复。当我对文件内容执行cfdump时,我得到以下结果,
类名:java.io.ByteArrayOutputStream方法:close()返回void reset()返回void size()返回int-toByteArray()返回byte[]toString(java.lang.String)返回java.lang.String toString()返回java.lang.String toString(int)返回java.lang.String write(byte[],int,int)返回void write(int)返回void writeTo(java.io.OutputStream)当我调用
toByteArray()
获取二进制数据时返回void
。然后我将数据保存到一个文件中,我看到了文件的xml和pdf部分。如果我获取结果并执行
binaryDecode
我会得到
ByteArray对象无法转换为字符串。
BinaryEncode
有效。你能给我们发邮件的URL吗,我们可以试试吗?@Leigh-我明天会做这个。你的建议是在我得到我发布的解决方案后提出的。我对mtom的回答很好奇,所以有两个问题:)1。在添加gzip、deflate(二进制数组)之后,您得到了什么类型的对象?如果是,它是否具有与以前相同的多部分内容?2.您如何确定起始/结束位置?如果它可以是动态的(比如MimeMultipart),这将是一个很好的解决方案。关于边界标记,您是否转储了cfhttp结果并检查了其他标头?可能包含在“内容类型”中。很高兴它成功了。仅供参考,S.O.线程是为了每个人的利益而归档的,因此我做了一些编辑,为将来的读者提供更多信息:)(还添加了一个链接,指向我阅读该想法的地方,以给予原作者信任)。你可以随意改变。
<cfscript>
    // Modify path as needed
    saveToDirec = "c:\temp\";

    // Hard coded "boundary" value for DEMO purposes. It MUST match actual value used in cfhttp response
    // Best to use cfhttp.responseHeader.content-Type so [if] the service changes your code won't break.
    contentType = "multipart/related; boundary=MIME_Boundary;";  

    // Load and parse ByteArrayOutputStream returned by CFHTTP
    dataSource = createObject("java", "javax.mail.util.ByteArrayDataSource").init(m_strSoapResponse.fileContent.toByteArray(), javaCast( "string", contentType));
    mimeParts = createObject("java", "javax.mail.internet.MimeMultipart").init(dataSource);

    for (i = 0; i < mimeParts.getCount(); i++) {
        writeOutput("<br>Processing part["& i &"]");
        bp = mimeParts.getBodyPart( javacast("int", i));

        // If this part is a PDF, save it to a file.
        if (!isNull(bp) && bp.isMimeType("application/pdf")) {
            outputFile = createObject("java", "java.io.File").init(saveToDirec &"demo_savedfile_"& i &".pdf");
            bp.saveFile(outputFile);
            writeOutput("<br>Saved: "& outputFile.getAbsolutePath());
        }
    }
</cfscript>