简体   繁体   English

用于上传文件的Java HTTP客户端(multipart / form-data)

[英]Java HTTP Client for Uploading Files (multipart/form-data)

I'm trying implement an HTTP client that makes multipart requests for uploading files to a HTTP server. 我正在尝试实现一个HTTP客户端,该客户端发出多部分请求以将文件上载到HTTP服务器。 The HTML form has three input fields: one for the username, one for the password and one for the file. HTML表单有三个输入字段:一个用于用户名,一个用于密码,一个用于文件。 The server side looks as follows. 服务器端如下所示。

<html>
<head>
<title>Uploader</title>
</head>

<body>
   <div id="header">
         <h1>Uploader</h1>
   </div>
   <div id="content">
         <form id="uploadformular" action="upload" method="post"
                enctype="multipart/form-data" accept-charset="utf-8">
                <div class="block">
                       <label for="user">Username</label> <input type="text" id="user"
                              name="myuser" required />
                </div>
                <div class="block">
                       <label for="password">Password</label> <input type="password" id="pin"
                              name="mypassword" required />
                </div>
                <div class="block">
                       <label for="file">ZIP File</label> <input type="file" id="file"
                              name="myfile" required />
                </div>
                <div>
                       <input type="submit" value="Upload" />
                </div>
         </form>
   </div>

</body>
</html>

My implementation is as follows. 我的实现如下。

public class MultipartUploader {

    private static final String CHARSET = "UTF-8";

    private static final String CRLF = "\r\n";

    public String httpUpload(String url, String filename, byte[] byteStream)
        throws MalformedURLException, IOException {

        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        final String boundary = Strings.repeat("-", 15) + Long.toHexString(System.currentTimeMillis());

        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Cache-Control", "no-cache");
        connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

        OutputStream directOutput = connection.getOutputStream();
        PrintWriter body = new PrintWriter(new OutputStreamWriter(directOutput, CHARSET), true);

        body.append(CRLF);
        addSimpleFormData("myuser", "myUserName", body, boundary);
        addSimpleFormData("mypassword", "mySecretPassword", body, boundary);
        addFileData("myfile", filename, byteStream, body, directOutput, boundary);
        addCloseDelimiter(body, boundary);

        int responseCode = connection.getResponseCode();
        String responseMessage = connection.getResponseMessage();

        String payload = CharStreams.toString(new InputStreamReader(connection.getInputStream()));
        return payload;
    }

    private static void addSimpleFormData(String paramName, String wert, PrintWriter body,
        final String boundary) {

        body.append(boundary).append(CRLF);
        body.append("Content-Disposition: form-data; name=\"" + paramName + "\"").append(CRLF);
        body.append("Content-Type: text/plain; charset=" + CHARSET).append(CRLF);
        body.append(CRLF);
        body.append(wert).append(CRLF);
        body.flush();
    }

    private static void addFileData(String paramName, String filename, byte[] byteStream, PrintWriter body,
        OutputStream directOutput, final String boundary) throws IOException {

        body.append(boundary).append(CRLF);
        body.append("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + filename + "\"")
            .append(CRLF);
        body.append("Content-Type: application/octed-stream").append(CRLF);
        body.append("Content-Transfer-Encoding: binary").append(CRLF);
        body.append(CRLF);
        body.flush();

        directOutput.write(byteStream);
        directOutput.flush();

        body.append(CRLF);
        body.flush();
    }

    private static void addCloseDelimiter(PrintWriter body, final String boundary) {

        body.append(boundary).append("--").append(CRLF);
        body.flush();
    }
}

The server responds with 200 OK . 服务器响应200 OK The problem I have is that somehow the HTTP body is not correctly created so that the response I get from the server says that not all fields of the form are set. 我遇到的问题是,不正确地创建了HTTP正文,以便我从服务器获得的响应表明并非所有表单字段都已设置。 The server doesn't say which field it is. 服务器没有说明它是哪个字段。 So my question is do you see any problem with this code? 所以我的问题是你看到这个代码有什么问题吗? Do I create the multipart request correctly? 我是否正确创建了多部分请求?

I also tried to upload a file using cURL with the following command and it worked. 我还尝试使用cURL上传一个文件,并使用以下命令。

cURL -F "myuser=myUserName" -F "mypassword=mySecretPassword" -F "myfile=@/path/to/my/file.zip" "http://abcdef.gh:1234/path/to/uploader"

Your boundaries between parts of data are missing extra two dashes in the beginning: -- 您在数据部分之间的界限在开头缺少额外的两个破折号: --

I've found this by capturing requests to http://httpbin.org/post made via your program and curl and comparing them via diff tool. 我通过捕获http://httpbin.org/post的请求来找到这个,通过你的程序和curl并通过diff工具进行比较。 I used Wireshark for capturing the requests. 我用Wireshark来捕获请求。

Here's how you can fix this: 以下是解决此问题的方法:

private static void addSimpleFormData(String paramName, String wert, PrintWriter body,
                                      final String boundary) {

    body.append("--").append(boundary).append(CRLF);
    body.append("Content-Disposition: form-data; name=\"" + paramName + "\"").append(CRLF);
    body.append("Content-Type: text/plain; charset=" + CHARSET).append(CRLF);
    body.append(CRLF);
    body.append(wert).append(CRLF);
    body.flush();
}

private static void addFileData(String paramName, String filename, byte[] byteStream, PrintWriter body,
                                OutputStream directOutput, final String boundary) throws IOException {

    body.append("--").append(boundary).append(CRLF);
    body.append("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + filename + "\"")
            .append(CRLF);
    body.append("Content-Type: application/octed-stream").append(CRLF);
    body.append("Content-Transfer-Encoding: binary").append(CRLF);
    body.append(CRLF);
    body.flush();

    directOutput.write(byteStream);
    directOutput.flush();

    body.append(CRLF);
    body.flush();
}

private static void addCloseDelimiter(PrintWriter body, final String boundary) {
    body.append("--").append(boundary).append("--").append(CRLF);
    body.flush();
}

Note extra .append("--") in the beginning of every method. 注意每个方法开头的额外.append("--")


see https://gist.github.com/shtratos/8e9570a4a5591b2bcecd55ca60b3f24f for full working code 有关完整的工作代码,请参阅https://gist.github.com/shtratos/8e9570a4a5591b2bcecd55ca60b3f24f

Is there a good reason why you are writing your own implementation rather than use the Apache HttpClient? 您是否有充分的理由编写自己的实现而不是使用Apache HttpClient?

See https://hc.apache.org/httpcomponents-client-ga/ 请参阅https://hc.apache.org/httpcomponents-client-ga/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 Java Http 客户端发送具有多部分/表单数据主体的 PUT 请求? - How to send a PUT request with multipart/form-data body with Java Http Client? 使用Apache HTTP客户端创建multipart / form-data实体 - Creating a multipart/form-data entity with Apache HTTP client Java库,用于读取包含多个文件的multipart / form-data http正文 - Java library for reading multipart/form-data http body containing multiple files 使用 java 创建一个 HTTP 多部分/表单数据请求 - creating an HTTP multipart/form-data request with java 使用多部分/表单数据将文件上传到服务器 - Uploading file to server with multipart/form-data 多部分/表单数据发布-Java Spring - Multipart/Form-Data Post - Java Spring 如何通过Java中的多部分表单数据上载时如何知道文件数 - How to know the file count when uploading via multipart form-data in java 使用Java上传具有multipart / form-data的zip文件时丢失字节 - Missing bytes when uploading zip file with multipart/form-data using java 使用Java中的multipart / form-data获取来自HTTP POST请求的数据 - Get data form HTTP POST request with multipart/form-data in Java (Spring) 与多部分/表单数据上传表单一起传递参数(Java Http 上传后) - Passing parameters along with a multipart/form-data upload form (Java Http Post Upload)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM