【问题标题】:How can I make a multipart/form-data POST request using Java?如何使用 Java 发出 multipart/form-data POST 请求?
【发布时间】:2010-11-25 14:55:00
【问题描述】:

在 Apache Commons HttpClient 版本 3.x 的日子里,发出 multipart/form-data POST 请求是可能的 (an example from 2004)。不幸的是,这在version 4.0 of HttpClient 中不再可能。

对于我们的核心活动“HTTP”,多部分有点 超出范围。我们很乐意使用由某些人维护的多部分代码 范围内的其他项目,但我不知道。 几年前,我们尝试将多部分代码移至 commons-codec 以前,但我没有在那里起飞。奥列格最近提到了另一个 具有多部分解析代码并且可能感兴趣的项目 在我们的多部分格式化代码中。不知道现在的状态 在那。 (http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html)

是否有人知道任何 Java 库允许我编写可以发出多部分/表单数据 POST 请求的 HTTP 客户端?

背景:我想使用Remote API of Zoho Writer

【问题讨论】:

标签: java http multipart


【解决方案1】:

你会快乐的!

   <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
   </dependency>
   <dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.3.1</version>
   </dependency>

import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;


byte[] byteArr1 = multipartFile1.getBytes();
byte[] byteArr2 = multipartFile2.getBytes();

HttpEntity reqEntity = MultipartEntityBuilder.create().setCharset(Charset.forName("UTF-8"))
                .addPart("image1", new ByteArrayBody(byteArr1, req.getMultipartFile1().getOriginalFilename()))
                .addPart("image2", new ByteArrayBody(byteArr2, req.getMultipartFile2().getOriginalFilename()))
                .build();

【讨论】:

    【解决方案2】:

    使用 HttpRequestFactory 到 jira xray 的 /rest/raven/1.0/import/execution/cucumber/multipart :

    Map<String, Object> params = new HashMap<>();
                params.put( "info", "zigouzi" );
                params.put(  "result", "baalo"  );
                HttpContent content = new UrlEncodedContent(params);
    
                OAuthParameters oAuthParameters = jiraOAuthFactory.getParametersForRequest(ACCESS_TOKEN, CONSUMER_KEY, PRIVATE_KEY);
                HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory(oAuthParameters);
                HttpRequest request = requestFactory.buildPostRequest(new GenericUrl(url),   content);
                request.getHeaders().setAccept("application/json");
                String boundary = Long.toHexString(System.currentTimeMillis());
                request.getHeaders().setContentType("multipart/form-data; boundary="+boundary);
                request.getHeaders().setContentEncoding("application/json");
                HttpResponse response = null ;
                try
                {
                    response = request.execute();
                    Scanner s = new Scanner(response.getContent()).useDelimiter("\\A");
                    result = s.hasNext() ? s.next() : "";
                }
                catch (Exception e)
                {
                     
                }
    

    成功了。

    【讨论】:

      【解决方案3】:

      我的代码使用多部分中的 post 将文件发送到服务器。 请求发送表单数据时使用多值映射

        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
              map.add("FILE", new FileSystemResource(file));
              map.add("APPLICATION_ID", Number);
      
         httpService.post( map,headers);
      
      

      在接收端使用

      @RequestMapping(value = "fileUpload", method = RequestMethod.POST)
          public ApiResponse AreaCsv(@RequestParam("FILE") MultipartFile file,@RequestHeader("clientId") ){
      //code
      }
      

      【讨论】:

        【解决方案4】:

        这是一个不需要任何库的解决方案。

        此例程将目录d:/data/mpf10 中的每个文件传输到urlToConnect

        
        String boundary = Long.toHexString(System.currentTimeMillis());
        URLConnection connection = new URL(urlToConnect).openConnection();
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
            File dir = new File("d:/data/mpf10");
            for (File file : dir.listFiles()) {
                if (file.isDirectory()) {
                    continue;
                }
                writer.println("--" + boundary);
                writer.println("Content-Disposition: form-data; name=\"" + file.getName() + "\"; filename=\"" + file.getName() + "\"");
                writer.println("Content-Type: text/plain; charset=UTF-8");
                writer.println();
                BufferedReader reader = null;
                try {
                    reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
                    for (String line; (line = reader.readLine()) != null;) {
                        writer.println(line);
                    }
                } finally {
                    if (reader != null) {
                        reader.close();
                    }
                }
            }
            writer.println("--" + boundary + "--");
        } finally {
            if (writer != null) writer.close();
        }
        // Connection is lazily executed whenever you request any status.
        int responseCode = ((HttpURLConnection) connection).getResponseCode();
        // Handle response
        

        【讨论】:

          【解决方案5】:

          我的代码将 multipartFile 发布到服务器。

            public static HttpResponse doPost(
              String host,
              String path,
              String method,
              MultipartFile multipartFile
            ) throws IOException
            {
          
              HttpClient httpClient = wrapClient(host);
              HttpPost httpPost = new HttpPost(buildUrl(host, path));
          
              if (multipartFile != null) {
          
                HttpEntity httpEntity;
          
                ContentBody contentBody;
                contentBody = new ByteArrayBody(multipartFile.getBytes(), multipartFile.getOriginalFilename());
                httpEntity = MultipartEntityBuilder.create()
                                                   .addPart("nameOfMultipartFile", contentBody)
                                                   .build();
          
                httpPost.setEntity(httpEntity);
          
              }
              return httpClient.execute(httpPost);
            }
          

          【讨论】:

            【解决方案6】:

            我在 Apache 的 Quickstart Guide 中找到了 this sample。适用于 4.5 版:

            /**
             * Example how to use multipart/form encoded POST request.
             */
            public class ClientMultipartFormPost {
            
                public static void main(String[] args) throws Exception {
                    if (args.length != 1)  {
                        System.out.println("File path not given");
                        System.exit(1);
                    }
                    CloseableHttpClient httpclient = HttpClients.createDefault();
                    try {
                        HttpPost httppost = new HttpPost("http://localhost:8080" +
                                "/servlets-examples/servlet/RequestInfoExample");
            
                        FileBody bin = new FileBody(new File(args[0]));
                        StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);
            
                        HttpEntity reqEntity = MultipartEntityBuilder.create()
                                .addPart("bin", bin)
                                .addPart("comment", comment)
                                .build();
            
            
                        httppost.setEntity(reqEntity);
            
                        System.out.println("executing request " + httppost.getRequestLine());
                        CloseableHttpResponse response = httpclient.execute(httppost);
                        try {
                            System.out.println("----------------------------------------");
                            System.out.println(response.getStatusLine());
                            HttpEntity resEntity = response.getEntity();
                            if (resEntity != null) {
                                System.out.println("Response content length: " + resEntity.getContentLength());
                            }
                            EntityUtils.consume(resEntity);
                        } finally {
                            response.close();
                        }
                    } finally {
                        httpclient.close();
                    }
                }
            }
            

            【讨论】:

              【解决方案7】:

              我们有一个多部分表单提交的纯 java 实现,不使用 jdk 之外的任何外部依赖项或库。参考https://github.com/atulsm/https-multipart-purejava/blob/master/src/main/java/com/atul/MultipartPure.java

              private static String body = "{\"key1\":\"val1\", \"key2\":\"val2\"}";
              private static String subdata1 = "@@ -2,3 +2,4 @@\r\n";
              private static String subdata2 = "<data>subdata2</data>";
              
              public static void main(String[] args) throws Exception{        
                  String url = "https://" + ip + ":" + port + "/dataupload";
                  String token = "Basic "+ Base64.getEncoder().encodeToString((userName+":"+password).getBytes());
              
                  MultipartBuilder multipart = new MultipartBuilder(url,token);       
                  multipart.addFormField("entity", "main", "application/json",body);
                  multipart.addFormField("attachment", "subdata1", "application/octet-stream",subdata1);
                  multipart.addFormField("attachment", "subdata2", "application/octet-stream",subdata2);        
                  List<String> response = multipart.finish();         
                  for (String line : response) {
                      System.out.println(line);
                  }
              }
              

              【讨论】:

                【解决方案8】:

                httpcomponents-client-4.0.1 为我工作。但是,我必须添加外部 jar apache-mime4j-0.6.jar (org.apache.james.mime4j) 否则 reqEntity.addPart("bin", bin); 不会编译。现在它就像魅力一样工作。

                【讨论】:

                  【解决方案9】:

                  我们使用 HttpClient 4.x 进行多部分文件发布。

                  更新:从 HttpClient 4.3 开始,一些类已被弃用。这是带有新 API 的代码:

                  CloseableHttpClient httpClient = HttpClients.createDefault();
                  HttpPost uploadFile = new HttpPost("...");
                  MultipartEntityBuilder builder = MultipartEntityBuilder.create();
                  builder.addTextBody("field1", "yes", ContentType.TEXT_PLAIN);
                  
                  // This attaches the file to the POST:
                  File f = new File("[/path/to/upload]");
                  builder.addBinaryBody(
                      "file",
                      new FileInputStream(f),
                      ContentType.APPLICATION_OCTET_STREAM,
                      f.getName()
                  );
                  
                  HttpEntity multipart = builder.build();
                  uploadFile.setEntity(multipart);
                  CloseableHttpResponse response = httpClient.execute(uploadFile);
                  HttpEntity responseEntity = response.getEntity();
                  

                  以下是 已弃用的 HttpClient 4.0 API 的原始 sn-p 代码:

                  HttpClient httpclient = new DefaultHttpClient();
                  HttpPost httppost = new HttpPost(url);
                  
                  FileBody bin = new FileBody(new File(fileName));
                  StringBody comment = new StringBody("Filename: " + fileName);
                  
                  MultipartEntity reqEntity = new MultipartEntity();
                  reqEntity.addPart("bin", bin);
                  reqEntity.addPart("comment", comment);
                  httppost.setEntity(reqEntity);
                  
                  HttpResponse response = httpclient.execute(httppost);
                  HttpEntity resEntity = response.getEntity();
                  

                  【讨论】:

                  • 啊,多部分的东西已经移到 org.apache.httpcomponents-httpmime-4.0 了!可以在某处提及:/
                  • 我试过你更新的代码,它适用于小文件,但不适用于大文件。你能帮我解决这个问题吗question
                  • 您好 ZZ,我已经对我的代码进行了上述更改,但是,我现在面临一个新问题 - 我的 REST 端点不接受请求。它需要以下参数:~@PathVariable final String id, @RequestParam("image") final MultipartFile image, @RequestParam("l") final String l, @RequestParam("lo") final String lo, @RequestParam(" bac") final String bac, @RequestParam("cac") final String cac, @RequestParam("m") final String m ... 以前,请求被接受。但现在我收到 500 错误。任何想法为什么会发生这种情况?
                  • 我编辑了答案,使代码示例不再水平滚动 --- 当我尝试在自己的工作中使用它时,滚动导致我错过了一个重要的最终参数。
                  • 这里是更新答案的 Maven 依赖项 org.apache.httpcomponentshttpclient4.3.6org.apache.httpcomponentshttpmime4.3.6
                  【解决方案10】:

                  使用此代码将图像或任何其他文件上传到使用多部分发布的服务器。

                  import java.io.File;
                  import java.io.IOException;
                  import java.io.UnsupportedEncodingException;
                  
                  import org.apache.http.client.ClientProtocolException;
                  import org.apache.http.client.HttpClient;
                  import org.apache.http.client.ResponseHandler;
                  import org.apache.http.client.methods.HttpPost;
                  import org.apache.http.entity.mime.MultipartEntity;
                  import org.apache.http.entity.mime.content.FileBody;
                  import org.apache.http.entity.mime.content.StringBody;
                  import org.apache.http.impl.client.BasicResponseHandler;
                  import org.apache.http.impl.client.DefaultHttpClient;
                  
                  public class SimplePostRequestTest {
                  
                      public static void main(String[] args) throws UnsupportedEncodingException, IOException {
                          HttpClient httpclient = new DefaultHttpClient();
                          HttpPost httppost = new HttpPost("http://192.168.0.102/uploadtest/upload_photo");
                  
                          try {
                              FileBody bin = new FileBody(new File("/home/ubuntu/cd.png"));
                              StringBody id = new StringBody("3");
                              MultipartEntity reqEntity = new MultipartEntity();
                              reqEntity.addPart("upload_image", bin);
                              reqEntity.addPart("id", id);
                              reqEntity.addPart("image_title", new StringBody("CoolPic"));
                  
                              httppost.setEntity(reqEntity);
                              System.out.println("Requesting : " + httppost.getRequestLine());
                              ResponseHandler<String> responseHandler = new BasicResponseHandler();
                              String responseBody = httpclient.execute(httppost, responseHandler);
                              System.out.println("responseBody : " + responseBody);
                  
                          } catch (ClientProtocolException e) {
                  
                          } finally {
                              httpclient.getConnectionManager().shutdown();
                          }
                      }
                  
                  }
                  

                  它需要以下文件才能上传。

                  图书馆是 httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jarcommons-logging-1.1.1.jar 在类路径中。

                  【讨论】:

                  • 感谢您提供库的版本
                  【解决方案11】:

                  如果 JAR 的大小很重要(例如,在 applet 的情况下),也可以直接将 httpmime 与 java.net.HttpURLConnection 一起使用,而不是 HttpClient。

                  httpclient-4.2.4:      423KB
                  httpmime-4.2.4:         26KB
                  httpcore-4.2.4:        222KB
                  commons-codec-1.6:     228KB
                  commons-logging-1.1.1:  60KB
                  Sum:                   959KB
                  
                  httpmime-4.2.4:         26KB
                  httpcore-4.2.4:        222KB
                  Sum:                   248KB
                  

                  代码:

                  HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                  connection.setDoOutput(true);
                  connection.setRequestMethod("POST");
                  
                  FileBody fileBody = new FileBody(new File(fileName));
                  MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.STRICT);
                  multipartEntity.addPart("file", fileBody);
                  
                  connection.setRequestProperty("Content-Type", multipartEntity.getContentType().getValue());
                  OutputStream out = connection.getOutputStream();
                  try {
                      multipartEntity.writeTo(out);
                  } finally {
                      out.close();
                  }
                  int status = connection.getResponseCode();
                  ...
                  

                  pom.xml 中的依赖关系:

                  <dependency>
                      <groupId>org.apache.httpcomponents</groupId>
                      <artifactId>httpmime</artifactId>
                      <version>4.2.4</version>
                  </dependency>
                  

                  【讨论】:

                  • FileBody 这是从哪里来的?有没有(简单的)方法不使用 apace.httpcomponents ?
                  【解决方案12】:

                  您还可以使用基于 HTTP 客户端的REST Assured。很简单:

                  given().multiPart(new File("/somedir/file.bin")).when().post("/fileUpload");
                  

                  【讨论】:

                  • 它将假定一个名为“文件”的控件名称。如果您有不同的控件名称,则需要指定它:multiPart("controlName", new File("/somedir/file.bin")),请参阅github.com/rest-assured/rest-assured/wiki/…
                  • REST Assured 具有出色的 API 并支持许多功能。与它一起工作是一种乐趣。但公平地说,值得一提的是,由于一些热身程序,您可能会在第一次调用时遇到性能下降。您可以在互联网上找到更多信息,即这里sqa.stackexchange.com/questions/39532/…
                  • REST Assured 是一个出色的库,但它是为 Web API 测试而设计的,我认为它不是在生产代码中进行 HTTP 调用的正确工具,尽管它当然使用相同的底层库。
                  【解决方案13】:

                  这些是我拥有的 Maven 依赖项。

                  Java 代码:

                  HttpClient httpclient = new DefaultHttpClient();
                  HttpPost httpPost = new HttpPost(url);
                  
                  FileBody uploadFilePart = new FileBody(uploadFile);
                  MultipartEntity reqEntity = new MultipartEntity();
                  reqEntity.addPart("upload-file", uploadFilePart);
                  httpPost.setEntity(reqEntity);
                  
                  HttpResponse response = httpclient.execute(httpPost);
                  

                  pom.xml 中的 Maven 依赖项:

                  <dependency>
                    <groupId>org.apache.httpcomponents</groupId>
                    <artifactId>httpclient</artifactId>
                    <version>4.0.1</version>
                    <scope>compile</scope>
                  </dependency>
                  <dependency>
                    <groupId>org.apache.httpcomponents</groupId>
                    <artifactId>httpmime</artifactId>
                    <version>4.0.1</version>
                    <scope>compile</scope>
                  </dependency>
                  

                  【讨论】:

                  • HttpEntity 类至少在 4.2 中也需要 httpcore
                  猜你喜欢
                  • 2019-04-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-06-19
                  • 2021-06-08
                  • 1970-01-01
                  相关资源
                  最近更新 更多