如何使用JDK11java.net.http.HttpClient上传文件?
How to upload files using JDK 11 java.net.http.HttpClient?
最近遇到了JDK自带的java.net.http.HttpClient的一些问题 11.不知道怎么用文件上传。在 java.net.http.BodyPublishers 中找到了 ofInputStream()。我不知道我是否使用这种方法上传文件。
下面是我写的例子。
public HttpResponse<String> post(String url, Supplier<? extends InputStream> streamSupplier, String... headers) throws IOException, InterruptedException {
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers(headers)
.POST(null == streamSupplier ?
HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofInputStream(streamSupplier));
HttpRequest request = builder.build();
log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(), request.uri().toString());
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
HttpRequest 类型提供工厂方法来创建请求发布者以处理正文类型,例如文件:
HttpRequest.BodyPublishers::ofFile(Path)
您可以更新您的方法:
public HttpResponse<String> post(String url, Path file, String... headers) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers(headers)
.POST(null == file ? HttpRequest.BodyPublishers.noBody() :
HttpRequest.BodyPublishers.ofFile(file))
.build();
log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(),
request.uri().toString());
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
java.net.http.HttpClient
处理通过 BodyPublisher
提供的字节作为原始 body 数据,没有任何解释。因此,无论您使用 HttpRequest.BodyPublishers::ofFile(Path)
还是 HttpRequest.BodyPublishers::ofByteArray(byte[])
在语义上都是无关紧要的:变化只是如何获取将要传输的字节。
在文件上传的情况下 - 您的服务器可能希望请求 body 以特定方式格式化。它还可能期望一些特定的 headers 与请求一起传输(例如 Content-Type
等)。 HttpClient
不会神奇地为您做到这一点。这是您需要在调用者级别实现的东西。
您可以通过以下方式使用方法:
public void uploadLocalFileToRemote(String notEncodedUrlStr, String remoteFilename, String localSourceDir, String localFilename) {
Path sourcePath = Path.of(localSourceDir, localFilename);
if(!sourcePath.toFile().canRead())
{
System.err.println("please check the local file existance/readability: " + sourcePath.toAbsolutePath());
return;
}
FileInputStream ins = null;
try {
ins = new FileInputStream(sourcePath.toFile());//FileNotFoundException extends IOException
BufferedInputStream buf_ins = new BufferedInputStream(ins);
Supplier<? extends InputStream> streamSupplier = new Supplier<BufferedInputStream>() {
@Override
public BufferedInputStream get() {
return buf_ins;
}
};
//HttpResponse<String> response = post(notEncodedUrlStr, streamSupplier,
HttpResponse<String> response = post(notEncodedUrlStr, () -> buf_ins,
"User-Agent", "Java 11 HttpClient Bot", "Content-type", "application/octet-stream",
"accept", "*/*", "fileName", remoteFilename);
// print response:
System.out.println(response.version().name() + " " + response.statusCode());
// print response headers
HttpHeaders headers = response.headers();
headers.map().forEach((k, v) -> System.out.println(k + ":" + v));
// print response body
String body = response.body();
System.out.println(body);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
另一个考虑因素是您的服务器端是如何实现的。这里假设服务器端将使用 http 1.1“分块”。并为 remoteFilename 配置目录。
最近遇到了JDK自带的java.net.http.HttpClient的一些问题 11.不知道怎么用文件上传。在 java.net.http.BodyPublishers 中找到了 ofInputStream()。我不知道我是否使用这种方法上传文件。 下面是我写的例子。
public HttpResponse<String> post(String url, Supplier<? extends InputStream> streamSupplier, String... headers) throws IOException, InterruptedException {
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers(headers)
.POST(null == streamSupplier ?
HttpRequest.BodyPublishers.noBody() : HttpRequest.BodyPublishers.ofInputStream(streamSupplier));
HttpRequest request = builder.build();
log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(), request.uri().toString());
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
HttpRequest 类型提供工厂方法来创建请求发布者以处理正文类型,例如文件:
HttpRequest.BodyPublishers::ofFile(Path)
您可以更新您的方法:
public HttpResponse<String> post(String url, Path file, String... headers) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.headers(headers)
.POST(null == file ? HttpRequest.BodyPublishers.noBody() :
HttpRequest.BodyPublishers.ofFile(file))
.build();
log.debug("Execute HttpClient Method:『{}』, Url:『{}』", request.method(),
request.uri().toString());
return client.send(request, HttpResponse.BodyHandlers.ofString());
}
java.net.http.HttpClient
处理通过 BodyPublisher
提供的字节作为原始 body 数据,没有任何解释。因此,无论您使用 HttpRequest.BodyPublishers::ofFile(Path)
还是 HttpRequest.BodyPublishers::ofByteArray(byte[])
在语义上都是无关紧要的:变化只是如何获取将要传输的字节。
在文件上传的情况下 - 您的服务器可能希望请求 body 以特定方式格式化。它还可能期望一些特定的 headers 与请求一起传输(例如 Content-Type
等)。 HttpClient
不会神奇地为您做到这一点。这是您需要在调用者级别实现的东西。
您可以通过以下方式使用方法:
public void uploadLocalFileToRemote(String notEncodedUrlStr, String remoteFilename, String localSourceDir, String localFilename) {
Path sourcePath = Path.of(localSourceDir, localFilename);
if(!sourcePath.toFile().canRead())
{
System.err.println("please check the local file existance/readability: " + sourcePath.toAbsolutePath());
return;
}
FileInputStream ins = null;
try {
ins = new FileInputStream(sourcePath.toFile());//FileNotFoundException extends IOException
BufferedInputStream buf_ins = new BufferedInputStream(ins);
Supplier<? extends InputStream> streamSupplier = new Supplier<BufferedInputStream>() {
@Override
public BufferedInputStream get() {
return buf_ins;
}
};
//HttpResponse<String> response = post(notEncodedUrlStr, streamSupplier,
HttpResponse<String> response = post(notEncodedUrlStr, () -> buf_ins,
"User-Agent", "Java 11 HttpClient Bot", "Content-type", "application/octet-stream",
"accept", "*/*", "fileName", remoteFilename);
// print response:
System.out.println(response.version().name() + " " + response.statusCode());
// print response headers
HttpHeaders headers = response.headers();
headers.map().forEach((k, v) -> System.out.println(k + ":" + v));
// print response body
String body = response.body();
System.out.println(body);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
另一个考虑因素是您的服务器端是如何实现的。这里假设服务器端将使用 http 1.1“分块”。并为 remoteFilename 配置目录。