【问题标题】:Http POST in Java (with file upload)Java中的Http POST(带文件上传)
【发布时间】:2012-03-13 21:05:55
【问题描述】:

我想做的是从 Java 应用程序提交一个 Web 表单。我需要填写的表格在这里:http://cando-dna-origami.org/

提交表单后,服务器会向给定的电子邮件地址发送一封确认电子邮件,现在我只是手动检查。我已经尝试手动填写表格,并且电子邮件可以正常发送。 (另外需要注意的是,当表单填写错误时,页面只是刷新,并没有给出任何反馈)。

我之前从来没有对http做过任何事情,但是我看了一会儿,想出了下面的代码,它应该向服务器发送一个POST请求:

    String data = "name=M+V&affiliation=Company&email="
            + URLEncoder.encode("m.v@gmail.com", "UTF-8")
            + "&axialRise=0.34&helixDiameter=2.25&axialStiffness=1100&bendingStiffness=230" +
            "&torsionalStiffness=460&nickStiffness=0.01&resolution=course&jsonUpload="
            + URLEncoder.encode("C:/Users/Marjie/Downloads/twisted_DNA_bundles/monotwist.L1.v1.json",
            "UTF-8") + "&type=square";

    URL page = new URL("http://cando-dna-origami.org/");
    HttpURLConnection con = (HttpURLConnection) page.openConnection();

    con.setDoOutput(true);
    con.setRequestMethod("POST");
    con.connect();

    OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
    out.write(data);
    out.flush();

    System.out.println(con.getResponseCode());
    System.out.println(con.getResponseMessage());

    out.close();
    con.disconnect();

但是,当它运行时,它似乎没有做任何事情——也就是说,我没有收到任何电子邮件,尽管程序确实向 System.out 打印“200 OK”,这似乎表明收到了一些东西来自服务器,虽然我不确定它的确切含义。我认为问题可能出在文件上传中,因为我不确定该数据类型是否需要不同的格式。

这是使用 Java 发送 POST 请求的正确方法吗?我需要为文件上传做一些不同的事情吗?谢谢!


看完Adam的帖子,我用Apache HttpClient,写了如下代码:

    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("type", "square"));
    //... add more parameters

    UrlEncodedFormEntity entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);

    HttpPost post = new HttpPost("http://cando-dna-origami.org/");
    post.setEntity(entity);

    HttpResponse response = new DefaultHttpClient().execute(post);
    post = new HttpPost("http://cando-dna-origami.org/");

    post.setEntity(new FileEntity(new File("C:/Users/Marjie/Downloads/twisted_DNA_bundles/monotwist.L1.v1.json"), "text/plain; charset=\"UTF-8\""));
    HttpResponse responseTwo = new DefaultHttpClient().execute(post);

但是,它似乎仍然无法正常工作;再次,我不确定上传的文件如何适合表单,所以我尝试发送两个单独的 POST 请求,一个带有表单,一个带有其他数据。我仍在寻找一种将这些组合成一个请求的方法;有人知道吗?

【问题讨论】:

    标签: java forms http post


    【解决方案1】:

    使用Apache HttpClient 之类的东西可能会更好,您可以使用它以编程方式构建POST 请求。

    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httppost = new HttpPost("http://.../whatever");
    
    List <NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("param1", "value1"));
    params.add(new BasicNameValuePair("param2", "value2"));
    ...
    
    httpost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
    
    HttpResponse response = httpclient.execute(httppost);
    

    如果您需要随表单上传文件,则需要使用MultipartEntity

    MultipartEntity reqEntity = new MultipartEntity();
    reqEntity.addPart("someParam", "someValue");
    reqEntity.addPart("someFile", new FileBody("/some/file"));
    ....
    
    httpost.setEntity(reqEntity);
    

    their site 上有一些示例程序。 “基于表单的登录”和“多部分编码请求实体”是很好的例子。

    也可能值得测试您的连接并查看底层网络数据以了解正在发生的情况。像Firebug 这样的东西可以让您准确地看到浏览器中发生的事情,并且您可以打开 HttpClient 日志以查看程序中交换的所有数据。或者,您可以使用诸如 Wireshark 或 Fiddler 之类的工具来实时查看您的网络流量。这可能会让您更好地了解您的浏览器在做什么,而不是您的程序在做什么。

    【讨论】:

    • 感谢您的建议!我下载了 Apache HttpClient 并使用它编写了一段不同的代码;不幸的是,它似乎仍然没有做任何事情。问题仍然是我不确定如何结合表单和文件上传。见上文
    • 因此,我建议您查看通过 HTTP 连接的基础数据(我的答案的最后一段),因为这将阐明浏览器使用(有效)和您的程序(不起作用)
    • 现在我明白了。我已使用有关添加文件上传的信息更新了答案。
    • DefaultHttpClient() 方法已被弃用,所以不是:HttpClientBuilder.create().build();
    • 而且 MultipartEntity 也已被弃用,因此请使用:MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    【解决方案2】:

    由于大多数建议的 Java HTTP POST 请求代码都无法运行,因此我决定向您提供完全可运行的代码,我相信您会发现这些代码对您将来创建任何基于 Java 的 POST 请求很有帮助。

    此 POST 请求是 multipart 类型,以允许向服务器发送/上传文件。

    多部分请求由一个主标头和一个名为 boundary 的分隔符字符串组成,用于区分每个部分(此分隔符将出现在流中,前面带有“--”(两个破折号)字符串,并且每个部分都有自己的小标题来告诉它的类型和更多的元数据。

    我的任务是使用一些在线服务创建一个 PDF 文件,但所有的多部分 POST 示例都没有成功...

    我需要将 HTML 文档及其图片、JS 和 CSS 文件打包到 ZIP/TAR 文件中,将其上传到在线 html2pdf 转换服务,并将结果作为 PDF 文档返回给我作为响应(流) 来自服务。

    我使用以下代码检查的当前服务是:Htmlpdfapi.com,但我相信只要稍作调整,您就可以将其与任何其他服务一起使用。

    方法调用(针对该服务)看起来像: [class instance name].sendPOSTRequest("http://htmlpdfapi.com/api/v1/pdf", "Token 6hr4-AmqZDrFVjAcJGykjYyXfwG1wER4", "/home/user/project/srv/files/example.zip", "result.pdf");

    这是我的代码,经过检查并且 100% 有效:

    public void sendPOSTRequest(String url, String authData, String attachmentFilePath, String outputFilePathName)
    {
        String charset = "UTF-8";
        File binaryFile = new File(attachmentFilePath);
        String boundary = "------------------------" + Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
        String CRLF = "\r\n"; // Line separator required by multipart/form-data.
        int    responseCode = 0;
    
        try 
        {
            //Set POST general headers along with the boundary string (the seperator string of each part)
            URLConnection connection = new URL(url).openConnection();
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.addRequestProperty("User-Agent", "CheckpaySrv/1.0.0");
            connection.addRequestProperty("Accept", "*/*");
            connection.addRequestProperty("Authentication", authData);
    
            OutputStream output = connection.getOutputStream();
            PrintWriter writer  = new PrintWriter(new OutputStreamWriter(output, charset), true);
    
            // Send binary file - part
            // Part header
            writer.append("--" + boundary).append(CRLF);
            writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
            writer.append("Content-Type: application/octet-stream").append(CRLF);// + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
            writer.append(CRLF).flush();
    
            // File data
            Files.copy(binaryFile.toPath(), output);
            output.flush(); 
    
            // End of multipart/form-data.
            writer.append(CRLF).append("--" + boundary + "--").flush();
    
            responseCode = ((HttpURLConnection) connection).getResponseCode();
    
    
            if(responseCode !=200) //We operate only on HTTP code 200
                return;
    
            InputStream Instream = ((HttpURLConnection) connection).getInputStream();
    
            // Write PDF file 
            BufferedInputStream BISin = new BufferedInputStream(Instream);
            FileOutputStream FOSfile  = new FileOutputStream(outputFilePathName);
            BufferedOutputStream out  = new BufferedOutputStream(FOSfile);
    
            int i;
            while ((i = BISin.read()) != -1) {
                out.write(i);
            }
    
            // Cleanup
            out.flush();
            out.close();
    
    
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      我目前正在编写一个小型 Web 服务器,并测试了您的请求客户端。我的服务器正在接收以下请求:

      User-Agent: Java/1.6.0_20 
      Host: localhost:1700 
      Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 
      Connection: keep-alive 
      Content-type: application/x-www-form-urlencoded 
      Content-Length: 287 
      name=M+V&affiliation=Company&email=m.v%40gmail.com&axialRise=0.34&helixDiameter=2.25&axialStiffness=1100&bendingStiffness=230&torsionalStiffness=460&nickStiffness=0.01&resolution=course&jsonUpload=C%3A%2FUsers%2FMarjie%2FDownloads%2Ftwisted_DNA_bundles%2Fmonotwist.L1.v1.json&type=square
      

      你应该检查你发送的 POST 数据的格式,很可能它没有像你期望的那样被服务器处理。

      【讨论】:

      • 感谢您的回答和测试代码!我发送的“POST 数据”到底是什么意思?您是指仅表单数据,还是客户端和连接数据?很抱歉,我不明白您在密码框中发布的信息的意义。连接设置有问题吗?
      • 我指的是带有表单数据的“数据”变量。框中的数据代表服务器接收到的标头和内容。
      【解决方案4】:

      你应该明确地使用 apaches HTTPClient 来完成这项工作!它使生活更轻松。这是一个如何使用 apaches HttpClient 上传文件的示例。

      byte[] data = outStream.toByteArray()
      HttpClient client = new DefaultHttpClient();
      HttpPost httpPost = new HttpPost("http://localhost:8080/YourResource");
      
      ByteArrayBody byteArrayBody = new ByteArrayBody(data, "application/json", "some.json");
      MultipartEntity multipartEntity = new MultipartEntity();
      multipartEntity.addPart("upload", byteArrayBody);
      httpPost.setEntity( multipartEntity );
      
      HttpResponse response = client.execute(httpPost);
      Reader reader = new InputStreamReader(response.getEntity().getContent());
      

      如果您还有其他问题,请告诉我。

      【讨论】:

        【解决方案5】:

        这是一个使用 apache httpclient 的示例。另外,不要忘记添加这些依赖项:

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

        代码:

        HttpClient httpclient = HttpClientBuilder.create().build();         
        HttpPost httppost = new HttpPost(DataSources.TORRENT_UPLOAD_URL);
        
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
                    builder.addPart("a_field_name", new FileBody(torrentFile));
        
        HttpEntity entity = builder.build();
        
        httppost.setEntity(entity);
        
        HttpResponse response = httpclient.execute(httppost);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-18
          • 2019-02-23
          • 1970-01-01
          • 2019-10-16
          • 2010-11-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-04
          相关资源
          最近更新 更多