问题
I am doing a CFHTTP post to a web service that is returning two parts (multipart), a XML and PDF. I am looking to get only the PDF. My cfhttp.filecontent
is a java.io.ByteArrayOutputStream
type. When I do a toString()
I get the following
Part 1
Content-Type: application/xop+xml; type="text/xml"; charset=utf-8
Content-Transfer-Encoding: 8bit
Part 2
Content-Type: application/pdf
Content-Transfer-Encoding: binary
I get the response in cfhttp.fileContent and the data looks like the following
--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--
I tried to remove all the data that's not related to the PDF but it's still not a valid binary file.
Any thoughts?
From the comments
When I do a cfdump
on the fileContent
I get the following:
Class Name: java.io.ByteArrayOutputStream
Methods:
close() returns void
reset() returns void
size() returns int
toByteArray() returns byte[]
toString(java.lang.String) returns java.lang.String
toString() returns java.lang.String
toString(int) returns java.lang.String
write(byte[], int, int) returns void
write(int) returns void
writeTo(java.io.OutputStream) returns void
When I invoke toByteArray()
I get binary data. I then save the data to a file and I see both XML and PDF parts of the file.
回答1:
The workaround required two changes: a change to set the accepted encoding value to gzip,deflate and to work with binary data using java.
<cfhttpparam type="HEADER" name="Accept-Encoding" value="gzip,deflate">
Second I needed to manipulate the response using binary methods.
binResponse = result.fileContent.toByteArray();
Next I used a utility from Ben Nadel, Binary.cfc, that has all the binary manipulation I needed. I used the method binarySlice()
to extract the start and end part of the binary. The sliced data contains the binary in the exact format that I needed. It was not base64 or any another type, it was binary.
sliced = binNadel.binarySlice( binResponse, <int posistion to start slice>, <int length of binary>));
This solution works, but it's ripe with potential issues, for example the order of the response could switch, the boundary name could change, etc. So this will require a lot of error handling to ensure smooth sailing.
Update:
Next I looked into Leigh's example to see if I could simplify my code. They suggested using Java's MimeMultipart class which supports parsing an MTOM multipart response. Here is the final working code:
<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>
Thanks all for your input!
来源:https://stackoverflow.com/questions/43594950/how-to-read-multipart-response-in-coldfusion