Retrofit中如何控制响应体?避免PDF响应解析失败问题
解决Retrofit解析PDF字节流失败的问题
这个问题太常见了——Retrofit默认配置了GSON转换器,它只会乖乖处理JSON格式的数据,碰到PDF这种二进制字节流肯定会“罢工”抛出异常。核心解决思路就是让Retrofit跳过自动反序列化步骤,直接获取原始的响应体,具体操作如下:
1. 修改Retrofit接口的返回类型
把你原来接口里返回的Call<YourCustomModel>(或者其他自定义模型类)改成Call<ResponseBody>,这样Retrofit就不会调用GSON去解析响应内容,而是直接返回原始的响应体对象。
示例代码:
// 原来的接口(会触发GSON解析,导致失败) // @POST("pdf-download") // Call<YourModel> fetchPdf(@Body RequestBody request); // 修改后的接口 @POST("pdf-download") Call<ResponseBody> fetchPdf(@Body RequestBody request);
如果你的项目用了Kotlin协程,对应的接口可以写成:
@POST("pdf-download") suspend fun fetchPdf(@Body request: RequestBody): ResponseBody
2. 处理原始响应体获取PDF字节流
在回调(或协程代码块)中,你可以通过ResponseBody的bytes()方法直接获取PDF的原始字节数组,或者用byteStream()获取输入流来处理(适合大文件,避免内存占用过高)。
Java回调示例:
fetchPdfCall.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { ResponseBody body = response.body(); if (body != null) { try { // 获取PDF字节数组 byte[] pdfBytes = body.bytes(); // 这里可以把字节数组保存为文件,或者传递给PDF查看器 savePdfToFile(pdfBytes, "/sdcard/downloads/result.pdf"); } catch (IOException e) { e.printStackTrace(); } finally { // 务必关闭ResponseBody,避免资源泄漏 body.close(); } } } else { // 处理请求不成功的情况(比如状态码非2xx) Log.e("PDF Fetch", "Request failed with code: " + response.code()); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { // 处理网络异常等情况 t.printStackTrace(); } });
Kotlin协程示例:
lifecycleScope.launch { try { val responseBody = fetchPdf(requestBody) val pdfBytes = responseBody.bytes() // 处理PDF字节 savePdfToFile(pdfBytes, "/sdcard/downloads/result.pdf") responseBody.close() } catch (e: IOException) { e.printStackTrace() } catch (e: Exception) { // 处理其他异常 } }
关键原理说明
Retrofit会根据你配置的Converter Factory(比如GsonConverterFactory.create())自动反序列化响应体。当接口返回类型是自定义模型时,Retrofit会尝试用GSON把响应内容转成模型对象,但PDF是二进制数据,完全不符合JSON格式,所以必然会抛出解析异常。而ResponseBody是Retrofit的原始响应载体,不会经过任何Converter处理,因此能直接拿到服务器返回的原始字节流。
内容的提问来源于stack exchange,提问作者LordDoskias
相关产品推荐
相关产品推荐

