我有一个InputStream
和将要输出的数据的大小(HTTP请求的响应)。由于空间的复杂性,我无法阅读全部内容。我想要的是将数据直接发送到一个新的请求主体中。我试过用OkHttp做这件事,但我无法让它工作。我不知道有任何其他HTTP客户端可以做到这一点。
如果可能的话,我想避免在Socket
上捣乱。有什么建议吗?
编辑:增加的限制是该解决方案必须与Java 8 一起使用
我相信Java 11中标准化的新HttpClient
应该可以让您做到这一点。它使用Flow
API(反应流),您可以提供一个BodyHandler
/BodySubscriber
,它将在字节到来时请求/接收字节。HttpClient
还允许您在发送请求时指定BodyPublisher
。因此,只需要将请求发布者转发给其订阅者的订阅绑定到Http堆栈分发给BodySubscriber
的订阅,然后让BodySubscriber
的onNext
(等等)调用Publisher
的订阅者对应方法。请注意,这是一个学术描述:我还没有真正尝试过实现它。设置订阅链接可能需要一些思考和技巧,但我相信它应该有效。
但是,请确保BodySubscriber
/BodyPublisher
的实现遵守响应流语义,并且它们不会阻塞回调。
https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpClient.htmlhttps://openjdk.java.net/groups/net/httpclient/intro.html
转念一想,也许这不是你的要求:如果你已经有了InputStream
,那就更简单了:在发送请求时只需使用BodyPublishers.ofInputStream
。
https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpRequest.BodyPublishers.html#ofInputStream(java.util.function.Supplier)
我想补充一点,如果请求的大小足以让您想要实现流式传输,那么接收服务很可能也想要实现流。
同样正确的是,虽然旧的现有HttpUrlConnection类或任何提供对与给定Url连接相关联的输入和输出流的访问的类都可以支持流式传输,但也可能需要为OPTIONS等新的安全问题编写过多的支持代码。
您可以这样做:
File file = new File("path_to_file"); // specify path to the large file you want to upload
InputStream inputStream = new FileInputStream(file); // Create input stream out of the file. This will be used to stream data directly to request body
HttpURLConnection connection = (HttpURLConnection) new URL("remote_url").openConnection(); // Open connection. This will not send eny request until explicitly asked.
connection.setDoOutput(true); // This will set http method to POST
connection.setFixedLengthStreamingMode(file.length()); // Define the length of the request body size
OutputStream output = connection.getOutputStream(); // This is the output stream of the request body. It will be used to stream file bytes into.
var bytes = inputStream.readNBytes(1024); // Read the first 1024 bytes from the file
// Following while loop will read chunks of 1024 bytes from the file and write them into the request body output stream.
// Note the use of the flush function. It will send the current content of the output stream to the remote server.
while (bytes.length > 0) {
output.write(bytes);
output.flush();
bytes = inputStream.readNBytes(1024);
}
connection.connect(); // This finishes request and returns response
我用它来集成Flussonic,它完成了任务。
您可以使用此答案进行进一步研究:https://stackoverflow.com/a/2793153/11676066