使用Flask作为服务端、OkHttp作为客户端时无法接收完整图片如何解决?
问题根因及解决方法
1 核心问题定位
你出现半截图片的核心原因是跨线程读取OkHttp响应流:OkHttp的Callback#onResponse方法运行在子线程,你把Response对象直接传入runOnUiThread的异步任务中,等UI线程执行读取流的操作时,onResponse方法已经执行完毕,OkHttp默认会自动关闭响应流资源,导致你只能读到部分流数据。
网页端能正常加载、同代码下载互联网图片正常的原因:
- 网页端HTTP客户端会自动完整读取所有响应数据再渲染,不会提前释放流
- 公共互联网图片服务一般都会返回标准的
Content-Length响应头,且你之前的下载逻辑大概率是在onResponse子线程直接读取流,没有跨线程传递Response对象
2 客户端代码修改(优先操作)
不要在UI线程读取响应流,先在onResponse子线程将所有响应数据读取为字节数组,再传入UI线程解析Bitmap,修改后代码如下:
void postRequest(String postUrl, RequestBody postBody) { // 建议OkHttpClient全局单例,不要每次请求新建实例,避免连接池异常 OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(postUrl) .post(postBody) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { call.cancel(); Log.d("FAIL", e.getMessage()); runOnUiThread(new Runnable() { @Override public void run() { TextView responseText = findViewById(R.id.responseText); responseText.setText(R.string.ip_failure); } }); } @Override public void onResponse(Call call, final Response response) throws IOException { // 子线程先读取完整字节数组,再传递到UI线程 final byte[] imgBytes = response.body().bytes(); runOnUiThread(new Runnable() { @Override public void run() { TextView responseText = findViewById(R.id.responseText); responseText.setText(""); try { Bitmap imagenGAN = BitmapFactory.decodeByteArray(imgBytes, 0, imgBytes.length); ImageView imagen = findViewById(R.id.imageView); imagen.setImageBitmap(imagenGAN); SaveImage(imagenGAN); }catch(Exception e){ Log.e("IMG_PARSE", "图片解析失败", e); } } }); } }); }
3 服务端可选优化
如果修改客户端后仍有问题,检查Flask返回响应是否携带正确的Content-Length头,部分场景下Flask启用gzip压缩或者流式传输时,不会返回正确的长度,导致客户端提前终止读取,修改服务端返回逻辑:
import os from flask import send_file # 以send_file为例,send_from_directory同理 file_path = "目标图片路径" resp = send_file(file_path) # 手动设置正确的文件长度 resp.headers["Content-Length"] = str(os.path.getsize(file_path)) # 关闭图片的gzip压缩,图片本身已压缩,gzip无收益还可能引发传输异常 resp.headers["Content-Encoding"] = "identity" return resp
补充排查方式
可以在客户端读取字节数组后,打印imgBytes.length,和服务端源文件的大小对比:
- 如果长度一致:属于Bitmap解析问题,检查图片格式是否为Android支持的格式
- 如果长度不一致:属于传输问题,进一步检查服务端是否有反向代理、限流截断等配置
内容的提问来源于stack exchange,提问作者Ismael Sanchez Torres
相关产品推荐
相关产品推荐

