如何使用Java流式传输HTTP请求的正文



我有一个InputStream和将要输出的数据的大小(HTTP请求的响应)。由于空间的复杂性,我无法阅读全部内容。我想要的是将数据直接发送到一个新的请求主体中。我试过用OkHttp做这件事,但我无法让它工作。我不知道有任何其他HTTP客户端可以做到这一点。

如果可能的话,我想避免在Socket上捣乱。有什么建议吗?

编辑:增加的限制是该解决方案必须与Java 8 一起使用

我相信Java 11中标准化的新HttpClient应该可以让您做到这一点。它使用FlowAPI(反应流),您可以提供一个BodyHandler/BodySubscriber,它将在字节到来时请求/接收字节。HttpClient还允许您在发送请求时指定BodyPublisher。因此,只需要将请求发布者转发给其订阅者的订阅绑定到Http堆栈分发给BodySubscriber的订阅,然后让BodySubscriberonNext(等等)调用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

最新更新