[英]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.