从Java到Coldfusion的多部分文件传输 - 无前导边界:%PDF-1.4 [英] Multipart file transfer from Java to Coldfusion - no leading boundary: %PDF-1.4

查看:987
本文介绍了从Java到Coldfusion的多部分文件传输 - 无前导边界:%PDF-1.4的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的问题之前的一个小历史,我发布了一个问题关于使用HTML5的multipart / form-data上传多个文件到coldfusion。它的工作精美。
您可以将代码与CF10编译器隔离吗?



我们的客户终于要求我对RESTful函数进行一些单元测试,我已经完成了很多工作,但是我使用我上面设计的massUpload函数打了一个路障。



对于长期问题,请放下与问题相关的问题。





单元测试代码:

 调用sendHTTPrequest 
HashMap< String,String> map = new HashMap< String,String>();
HashMap< String,File> getFiles = getFirstFileList();
map.put(testMethod,MassUploadTest);
map.put(method,massUpload);
map.put(valueString1,valueString1);
map.put(valueString2,valueString2);
map.put(valueNumeric3,valueNumeric3);
map.put(valueBoolean4,valueBoolean4);
map.put(valueString5,valueString5);
map.put(valueBoolean6,valueBoolean6);
map.put(valueString7,valueString7);

try {
sendHTTPrequest(map,getFiles);
} catch(RuntimeException e){
throw new RuntimeException(massup error in massUpload\\\

+ e.getMessage());
}
//结束调用类代码

Coldfusion函数:

 < cffunction name =massUploadaccess =remotereturntype =string> 
< cfargument name =valueString1type =stringrequired =false>
< cfargument name =valueString2type =stringrequired =false>
< cfargument name =valueNumeric3type =numericrequired =falsedefault = 0>
< cfargument name =valueBoolean4type =booleanrequired =truedefault =false>
< cfargument name =valueString5type =stringrequired =false>
< cfargument name =valueBoolean6type =booleanrequired =falsedefault =true>
< cfargument name =valueString7type =stringrequired =true>

<!--- massUpload code --->
< / cffunction>

所以这里是导致主要问题的代码。我尝试了不同的方法来使POST工作,所以显然代码有问题。我试图这样做而无需下载多个软件/库,但如果没有其他方式,那么我会做必要的安排。



功能代码:

  // sendHTTPrequest方法代码
protected static final String BASE_URI =< webaddress> /rest.cfc;
protected static final String CHARSET =UTF-8;
protected String response;
protected int status;
protected String statusMessage;

protected void sendHTTPrequest(Map< String,String> map,Map< String,File> fileList){

Set< String> keys = map.keySet();
status = 0;
response = null;
String boundary =----+ System.currentTimeMillis();

try {
URL_CONNECTION = BASE_URL.openConnection();
HTTP_CONNECTION =(HttpURLConnection)(URL_CONNECTION);

//设置请求标头
HTTP_CONNECTION.setRequestMethod(POST);
URL_CONNECTION.setRequestProperty(Accept-Charset,CHARSET);
URL_CONNECTION.setRequestProperty(Content-type,multipart / form-data; boundary =+ boundary);

//设置发布请求
URL_CONNECTION.setDoOutput(true);

OutputStream output = URL_CONNECTION.getOutputStream();
ByteArrayOutputStream bOutput = new ByteArrayOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output,CHARSET),true);

for(String key:keys){
writer.write( - + boundary);
writer.write(lineFeed);
writer.write(Content-Disposition:form-data; name = \+ key +\);
writer.write(lineFeed);
writer.write(lineFeed);
writer.write(map.get(key));
writer.write(lineFeed);
}

FileInputStream inputStream;
for(Map.Entry< String,File> entry:fileList.entrySet()){
String name = entry.getKey();
writer.write( - + boundary);
writer.write(lineFeed);
writer.write(Content-Disposition:form-data;
+name = \allfiles\; filename = \+ name +\);
writer.write(lineFeed);

String contentType = URLConnection.guessContentTypeFromName(name);
writer.write(Content-Type:+ contentType);
writer.write(lineFeed);

writer.write(Content-Transfer-Encoding:binary);
writer.write(lineFeed);

writer.write(Content-Id:<+ boundary +>);
writer.write(lineFeed);
writer.write(lineFeed);

文件temp = entry.getValue();

byte [] buffer = FileUtils.readFileToByteArray(temp);
output.write(buffer,0,buffer.length);
output.flush();

writer.write(lineFeed);
}

writer.write( - + boundary + - );
writer.write(lineFeed);
writer.flush();

writer.close();

status = HTTP_CONNECTION.getResponseCode();
statusMessage = HTTP_CONNECTION.getResponseMessage();
if(status == SUCCESS){
response = IOUtils.toString(URL_CONNECTION.getInputStream(),URL_CONNECTION.getContentEncoding());
}
System.out.println(Finished test+ map.get(testMethod)+Status:+ status);
System.out.println(Response:+ response);
HTTP_CONNECTION.disconnect();

} catch(UnknownServiceException use){
throw new RuntimeException(不支持输出协议);
} catch(IOException ioe){
throw new RuntimeException(无法创建输出流);
}
}
//结束sendHTTPrequest方法代码

I看到在输出状态,响应和statusMessage,我得到一个500错误,null,内部服务器错误。



看看Coldfusion服务器,我看到:

  SEVERE:Servlet.service()for servlet [CFCServlet]在上下文中带有path [/] threw exception 
java.io。 IOException:损坏的表单数据:无前导边界:%PDF-1.4!= ------ 1429222349902
at com.oreilly.servlet.multipart.MultipartParser。< init>(MultipartParser.java:182)
...

massUpload可以处理不同类型的文件,因此,单元测试需要能够通过massUpload发送不同的文件类型,而不只是PDF。



欢迎任何对问题的深入了解。谢谢。

解决方案

(来自评论)





尝试在写入文件字节之前刷新作者:

  ... 
byte [] buffer = FileUtils.readFileToByteArray(temp);
writer.flush(); // flush stream here
output.write(buffer,0,buffer.length);
...

更新: b
$ b

为了澄清,原始错误的原因是,即使代码创建了一个PrintWriter与 autoFlush = true ,当 write()被调用时,它仍然不会自动保存文本到底层的OutputStream。 autoFlush 设置只会影响这些方法:


autoFlush - 如果为true,则 println printf 格式方法
将[自动]刷新输出缓冲区


结果,代码将文件内容写入流之前 边界标记,这会创建无效的HTTP POST。因此500错误。您可以使用像Fiddler这样的程序包嗅探器验证此操作:



原始 - (无效):

  POST http:// localhost:8888 / test.cfm HTTP / 1.1 
Accept-Charset:UTF-8
Content-Type:multipart / form -数据; boundary = 14cd4c75e24
...
Content-Length:65570

%PDF-1.4

2 0 obj< / Type / XObject / ColorSpace / DeviceGray / Subtype / Image / BitsPerComponent 8 / Width 612 / Length 11876 / Height 792 / Filter / FlateDecode>> stream

...更多二进制

--14cd4c75e24
Content-Disposition:form-data; name =allfiles; filename =file0.pdf
Content-Type:application / pdf
Content-Transfer-Encoding:binary
Content-Id:< 14cd4c75e24&


--14cd4c75e24--

在添加文件内容之前刷新作者



新代码(有效)

  POST http:// localhost:8888 / test.cfm HTTP / 1.1 
Accept-Charset:UTF-8
Content-Type:multipart / form-data; boundary = 14cd4c91d29
...
Content-Length:65570

--14cd4c91d29
Content-Disposition:form-data; name =allfiles; filename =file0.pdf
Content-Type:application / pdf
Content-Transfer-Encoding:binary
Content-Id:< 14cd4c91d29&

%PDF-1.4

2 0 obj< / Type / XObject / ColorSpace / DeviceGray / Subtype / Image / BitsPerComponent 8 / Width 612 / Length 11876 / Height 792 / Filter / FlateDecode>> stream
...

我认为 Content-Id 必须是唯一的。所以boundary可能不是Content-Id值的不错选择。


A little history before my question, I posted a question about uploading multiple files to coldfusion using HTML5's multipart/form-data. And its worked beautifully. Can you isolate code from being seen from CF10 compiler?

Our client has finally requested some unit tests for the RESTful functions that I have put together, and I've been able to get quite a lot done, but I've hit a roadblock with the massUpload function that I designed above.

Sorry for the long question, putting down what is relevant to the problem.

Here is the code in question:

Unit Test Code:

//Outside class calling sendHTTPrequest
HashMap<String,String> map = new HashMap<String,String>();
HashMap<String,File> getFiles = getFirstFileList();
map.put("testMethod", "massUploadTest");
map.put("method", "massUpload");
map.put("valueString1", valueString1);
map.put("valueString2", valueString2);
map.put("valueNumeric3", valueNumeric3);
map.put("valueBoolean4", valueBoolean4);
map.put("valueString5", valueString5);
map.put("valueBoolean6", valueBoolean6);
map.put("valueString7", valueString7);

try {                    
    sendHTTPrequest(map, getFiles);
} catch(RuntimeException e) {
    throw new RuntimeException("Fatal error in massUpload\n"
            + e.getMessage());
}
//End Call class code

Coldfusion function:

<cffunction name="massUpload" access="remote" returntype="string">    
    <cfargument name="valueString1"  type="string"  required="false">
    <cfargument name="valueString2"  type="string"  required="false">
    <cfargument name="valueNumeric3" type="numeric" required="false" default=0>
    <cfargument name="valueBoolean4" type="boolean" required="true"  default="false">
    <cfargument name="valueString5"  type="string"  required="false">
    <cfargument name="valueBoolean6" type="boolean" required="false" default="true">
    <cfargument name="valueString7"  type="string"  required="true">

    <!--- massUpload code --->
</cffunction>

So here is the code that is causing the major problems. I've tried different approaches to get the POST to work so obviously the code has problems. I'm trying to do this without downloading multiple software/libraries, but if there is no other way, then I'll make the necessary arrangements. Otherwise, would love to get this done with the standard Java library.

Function code:

//sendHTTPrequest method code
protected static final String BASE_URI = "<webaddress>/rest.cfc";
protected static final String CHARSET = "UTF-8";
protected String response;
protected int status;
protected String statusMessage;

protected void sendHTTPrequest(Map<String,String> map, Map<String, File> fileList) {

        Set<String> keys = map.keySet();
        status = 0;
        response = null;
        String boundary = "----" + System.currentTimeMillis();

        try {            
            URL_CONNECTION = BASE_URL.openConnection();
            HTTP_CONNECTION = (HttpURLConnection) (URL_CONNECTION);

            //Set the request headers
            HTTP_CONNECTION.setRequestMethod("POST");
            URL_CONNECTION.setRequestProperty("Accept-Charset", CHARSET);            
            URL_CONNECTION.setRequestProperty("Content-type", "multipart/form-data; boundary=" + boundary);

            //Set up a post request
            URL_CONNECTION.setDoOutput(true);

            OutputStream output = URL_CONNECTION.getOutputStream();
            ByteArrayOutputStream bOutput = new ByteArrayOutputStream();
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, CHARSET), true);

            for(String key : keys) {
                writer.write("--" + boundary);
                writer.write(lineFeed);
                writer.write("Content-Disposition: form-data; name=\"" + key + "\"");
                writer.write(lineFeed);
                writer.write(lineFeed);
                writer.write(map.get(key));
                writer.write(lineFeed);
            }

            FileInputStream inputStream;
            for(Map.Entry<String, File> entry : fileList.entrySet()){
                String name = entry.getKey();
                writer.write("--" + boundary);
                writer.write(lineFeed);
                writer.write("Content-Disposition: form-data; "
                        + "name=\"allfiles\"; filename=\"" + name + "\"");
                writer.write(lineFeed);

                String contentType = URLConnection.guessContentTypeFromName(name);
                writer.write("Content-Type: " + contentType);
                writer.write(lineFeed);    

                writer.write("Content-Transfer-Encoding: binary");
                writer.write(lineFeed);    

                writer.write("Content-Id: <" + boundary + ">");
                writer.write(lineFeed);  
                writer.write(lineFeed);  

                File temp = entry.getValue();

                byte[] buffer = FileUtils.readFileToByteArray(temp);
                output.write(buffer, 0, buffer.length);
                output.flush();

                writer.write(lineFeed);    
            }

            writer.write("--" + boundary + "--");
            writer.write(lineFeed);
            writer.flush();

            writer.close();

            status = HTTP_CONNECTION.getResponseCode();
            statusMessage = HTTP_CONNECTION.getResponseMessage();
            if(status == SUCCESS) {
                response = IOUtils.toString(URL_CONNECTION.getInputStream(), URL_CONNECTION.getContentEncoding());
            }
            System.out.println("Finished test " + map.get("testMethod") + " Status: " + status);
            System.out.println("Response: " + response);
            HTTP_CONNECTION.disconnect();

        } catch(UnknownServiceException use) {
            throw new RuntimeException("Protocol for the output is not supported");
        } catch(IOException ioe) {
            throw new RuntimeException("Unable to create the output stream");
        }
    }
//End sendHTTPrequest method code

I see in the output for status, response and statusMessage, that I get a 500 error, null, Internal Server Error.

Looking on the Coldfusion server I see:

SEVERE: Servlet.service() for servlet [CFCServlet] in context with path [/] threw exception 
java.io.IOException: Corrupt form data: no leading boundary: %PDF-1.4 != ------1429222349902
at com.oreilly.servlet.multipart.MultipartParser.<init>(MultipartParser.java:182)
...

massUpload can handle different types of files, but is looking specifically for PDFs. So the unit test needs to be able to send different file types through to massUpload, not just PDFs.

Any insight into the problem would be welcome. Thank you.

解决方案

(From comments)

Have you used a packet sniffer to see what the above actually generates?

Try flushing the writer just before you write the file bytes:

...
byte[] buffer = FileUtils.readFileToByteArray(temp);
writer.flush(); // flush stream here
output.write(buffer, 0, buffer.length);
...

Update:

Just to clarify, the reason for the original error is that even though the code creates a PrintWriter with autoFlush=true, it still does not automatically save text to the underlying OutputStream when write() is invoked. The autoFlush setting only affects these methods:

autoFlush - if true, the println, printf, or format methods will [automatically] flush the output buffer

As a result, the code writes the file content to the stream before the boundary markers, which creates an invalid HTTP POST. Hence the 500 error. You can verify this using a package sniffer like Fiddler:

Original - (Invalid):

POST http://localhost:8888/test.cfm HTTP/1.1
Accept-Charset: UTF-8
Content-Type: multipart/form-data; boundary=14cd4c75e24
...
Content-Length: 65570

%PDF-1.4
%    
2 0 obj <</Type/XObject/ColorSpace/DeviceGray/Subtype/Image/BitsPerComponent 8/Width 612/Length 11876/Height 792/Filter/FlateDecode>>stream

... more binary

--14cd4c75e24
Content-Disposition: form-data; name="allfiles"; filename="file0.pdf"
Content-Type: application/pdf
Content-Transfer-Encoding: binary
Content-Id: <14cd4c75e24>


--14cd4c75e24--

The solution is to flush the writer before adding the file content. That ensures the boundary markers are added in the correct location, so the generated POST content is valid.

New Code (Valid)

POST http://localhost:8888/test.cfm HTTP/1.1
Accept-Charset: UTF-8
Content-Type: multipart/form-data; boundary=14cd4c91d29
...
Content-Length: 65570

--14cd4c91d29
Content-Disposition: form-data; name="allfiles"; filename="file0.pdf"
Content-Type: application/pdf
Content-Transfer-Encoding: binary
Content-Id: <14cd4c91d29>

%PDF-1.4
%    
2 0 obj <</Type/XObject/ColorSpace/DeviceGray/Subtype/Image/BitsPerComponent 8/Width 612/Length 11876/Height 792/Filter/FlateDecode>>stream
...

As an aside, I believe Content-Id must be unique. So "boundary" probably is not a good choice for the Content-Id value.

这篇关于从Java到Coldfusion的多部分文件传输 - 无前导边界:%PDF-1.4的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆