使用HttpClient4上传文件时设置"Content-Type"头部时出现问题

3

我正在尝试上传文件(或多个文件)到我的servlet,该servlet使用Apache文件上传来处理和获取已发布的文件。

当我使用以下代码时,一切都很顺利,文件已发送和接收。

DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://myservice.com/servlet");

MultipartEntity entity2 = new MultipartEntity();
FileBody fileBody = new FileBody(new File("C:/docOut.pdf"));
entity2.addPart("file", fileBody);
post.setEntity(entity2);

HttpResponse httpResponse = client.execute(post);
System.out.println(EntityUtils.toString(httpResponse.getEntity()));

但是当我尝试上传文件并设置自己的“Content-Type”为推荐类型(或者仅使用Apache文件上传库接受的类型)时:
post.addHeader("Content-Type", "multipart/form-data");

我的servlet没有获得任何文件并抛出异常:

org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:931)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:349)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
at com.myservice.server.filerep.action.FileUploadFormAction.execute(FileUploadFormAction.java:54)
at com.myservice.server.filerep.web.FileRepServlet.doGet(FileRepServlet.java:34)
at com.myservice.server.filerep.web.FileRepServlet.doPost(FileRepServlet.java:41)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.handler.RequestLogHandler.handle(RequestLogHandler.java:49)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:647)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)

我知道上传文件的POST请求不应该在请求中包含边界"元素"以确定上传的字节块的顺序,但我认为HttpClient会向我的请求中添加所有必要的信息(类似于当我没有指定内容类型时)。
我的问题是:
1. 为什么添加"Content-Type"会破坏我的请求?HttpClient难道不会根据我定义的内容类型添加边界元素吗? 2. 我应该明确设置请求的"Content-Type"还是让库来处理它? 3. 如果我可以显式地设置"Content-Type",你能提供一个代码片段吗? 4. 如果我可以显式地设置"Content-Type",在POST到某些表单时,为什么应该使用和优先选择"multipart/form-data"而不是"application/x-www-form-urlencoded"?
PS:我找到了一些相关的问题,但没有解决我的问题:ContentType issue with commons-upload and httpcomponent client

如何查看MultipartForm请求的内容?

2个回答

2
如果您有表单数据enctype,您必须按照RFC 2388中指定的规则进行操作。多部分消息中的数据被视为实体,因此每个实体都必须具有标题(包括Content-DispositionContent-Type等)和边界。
对于问题1的回答,RFC规定如下:
与所有多部分MIME类型一样,每个部分都有一个可选的“Content-Type”,默认为text/plain。
对于2),正如提到的,每个多部分消息都必须具有标题,因此您必须指定您的Content-Type(如果您没有完全使用HttpClient库功能)。
对于3)和4),RFC规定如下:
如果要返回多个文件作为单个表单条目的结果,则应将它们表示为嵌入在“multipart/form-data”中的“multipart/mixed”部分。
希望这可以帮助您。

谢谢提供的链接 - 在阅读并使用HttpClient进行了几次测试后,我发现我的错误在于:当设置“Content-Type”时,我需要提供边界(post.addHeader("Content-Type", "multipart/form-data; boundary=randomBoundaryNotInAnyOfParts"),还需要向MultipartEntity提供相同的边界,否则HttpClient将在各个部分之间插入自己的随机边界。感谢您指引我正确的方向 :)。 - ljader
我也遇到了同样的情况,但不知道该怎么办。我希望MultipartEntity能够告诉HttpPost对象它是多部分、表单数据,并且有一些边界,这样我就不用自己设置内容类型了。我不太明白如何为实体提供边界 - MultipartEntity没有像setBoundary这样的方法。或者,如何获取随机生成的边界并将其指定在addHeader中 - 也没有getBoundary方法... - fedd

0

插入随机生成边界的类是HttpClient,而不是HttpPost。因此,您应该查看HttpClient的方法。


抱歉,我本来是想为反馈添加评论的,但是点错了按钮 :( - Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接