java - 如何在 HTTP/1.1 中接收分块响应,同时在 Java/Android 中向服务器发送数据
问题描述
我们正在构建一个应用程序,它可以实时记录用户的声音,并通过 HTTP 请求将记录的数据发送到服务器。当服务器实时处理数据时,它也会以分块的形式发回响应。简单来说,app 是一块一块地向服务器发送数据,同时它也一块块地接收服务器的响应。
请不要告诉我这是不可能的,因为我在 iOS 中有一个工作示例,它使用URLSession
withuploadTask
使用流对将数据实时发送到服务器,然后从这个回调中逐块接收响应urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
。
下面是我的 Java 代码。我得到了发送工作,但只有在发送完成后才会收到响应。
RequestBody body = new RequestBody()
{
@Override
public MediaType contentType()
{
return MediaType.get("application/octet-stream");
}
@Override
public void writeTo(BufferedSink sink) throws IOException
{
String filename = "/path/spoken.pcm";
try
{
InputStream inputStream = new DataInputStream(new FileInputStream(new File(filename)));
byte[] cacheBytes = new byte[320];
int length;
while((length = inputStream.read(cacheBytes, 0, cacheBytes.length)) != -1)
{
System.out.println("write thread name: " + Thread.currentThread());
sink.write(cacheBytes, 0, length);
Thread.sleep(10);
}
inputStream.close();
}
catch(IOException | InterruptedException e)
{
e.printStackTrace();
}
}
};
Request request = new Request.Builder()
.url("www.server.com")
.post(body)
.build();
Interceptor interceptor = new Interceptor()
{
@Override
public Response intercept(Chain chain) throws IOException
{
System.out.println("intercept!!!");
CountDownLatch latch = new CountDownLatch(1);
Response response = chain.proceed(chain.request());
BufferedSource source = response.body().source();
System.out.println("got response body !!!!");
new Thread(new Runnable()
{
@Override
public void run()
{
byte[] cachedBytes = new byte[512];
try
{
while(!source.exhausted())
{
int length = source.read(cachedBytes);
byte[] partialBytes = new byte[length];
System.arraycopy(cachedBytes, 0, partialBytes, 0, length);
System.out.println("partial response received: " + getHexString(partialBytes));
}
}
catch (IOException e)
{
e.printStackTrace();
}
latch.countDown();
}
}).start();
try
{
latch.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return response;
}
};
httpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
httpClient.newCall(request).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException
{
try(ResponseBody responseBody = response.body())
{
if(!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println("all responses received!");
}
}
});
此日志:System.out.println("got response body !!!!");
仅在我完成将所有数据发送到服务器时出现。这意味着,当writeTo(BufferedSink sink)
返回时,我会在拦截器回调中以块的形式获得响应,然后调用回调onResponse(Call call, Response response)
。
我需要的是,当我发送数据时,我希望能够同时获得分块响应。
解决方案
对于 HTTP/1.1,OkHttp 在请求正文完成传输之前不会返回响应正文。对于 HTTP/2,您可以覆盖isDuplex()以返回 true。
推荐阅读
- javascript - accounts-js GraphQL 客户端身份验证突变不起作用
- python - 是否有不同的方法来创建菜单栏?
- next.js - React 服务器不匹配:Prop `className` 不匹配
- c++ - 从 int 到具有非固定基础类型的作用域枚举的 constexpr 静态转换的未定义行为在 C++17 中编译
- python-sphinx - 创建 Sphinx reStructuredText 章节组
- c# - C# Visual Studio 用正常语法替换 => 的任何方式
- python - 使用来自日志文件的成功状态消息过滤和验证 IPv4 和 IPv6 的 Python 解决方案
- python-docx - 仅在一个表格行而不是整个文档上设置字体颜色
- mysql - 只返回 1 行?
- if-statement - Tableau - 满足 IF 条件的多个记录