【问题标题】:Problem with setting header "Content-Type" in uploading file with HttpClient4使用 HttpClient4 上传文件时设置标题“Content-Type”的问题
【发布时间】:2011-06-02 08:56:16
【问题描述】:

我正在尝试将文件(或多个文件)上传到我的 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不应该给我定义的content-type添加边界元素吗?

  2. 我应该明确地为我的请求设置“Content-Type”还是让库来处理它?

  3. 如果我可以明确设置Content-Type,你能提供一个代码sn-p吗?

  4. 如果我可以明确设置 Content-Type,为什么我应该使用“multipart/form-data”而不是“application/x-www-form-urlencoded”来发布某些表单?

PS:我发现了一些相关的问题,但没有解决我的问题:

ContentType issue with commons-upload and httpcomponent client

How can I See the content of a MultipartForm request?

【问题讨论】:

    标签: java file-upload httpclient


    【解决方案1】:

    如果您有表单数据编码类型,则必须遵循RFC 2388 中指定的规则。多部分消息中的数据被视为实体,因此每个实体都必须有一个标头(带有Content-DispositionContent-Type 等)和一个边界。

    关于回答问题 1,RFC 规定:

    与所有多部分 MIME 类型一样,每个 部分有一个可选的“内容类型”, 默认为 text/plain。

    对于 2),如前所述,每条多部分消息都必须有一个标头,因此您必须指定您的 Content-Type(如果您没有完全使用 HttpClient 库功能)。

    对于 3) 和 4) RFC 规定:

    如果要返回多个文件 作为单个表单条目的结果, 它们应该表示为 嵌入其中的“多部分/混合”部分 “多部分/表单数据”。

    希望这会有所帮助。

    【讨论】:

    • 感谢您的链接 - 在我阅读并使用 HttpClient 进行一些测试后,我发现我做错了什么:设置“Content-Type”时我需要提供边界(post.addHeader("Content -Type", "multipart/form-data; boundary=randomBoundaryNotInAnyOfParts") 我还需要为 MultipartEntity 提供相同的边界,否则 HttpClient 将在部分之间插入他自己的随机边界。Tnx 为我指出正确的方式:)。
    • 我也有同样的情况,但不知道该怎么做。我希望 MultipartEntity 会告诉 HttpPost 对象它是多部分的、表单数据并且有一些边界,并且我不会自己设置内容类型。我不太明白如何为实体提供边界——MultipartEntity 没有像 setBoundary 这样的方法。或者,如何让随机生成的边界由我自己在 addHeader 中指定 - 也没有 getBoundary 方法......
    【解决方案2】:

    对于 fedd/ 插入随机生成边界的类是 HttpClient,而不是 HttpPost。所以你应该看看 HttpClient 的方法

    【讨论】:

    • 对不起,我是想为 fedd 添加评论,但点击了错误的按钮 :(
    猜你喜欢
    • 2014-03-06
    • 2019-12-15
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 2013-07-22
    • 2015-06-21
    相关资源
    最近更新 更多