java.lang.IllegalStateException: closed when trying to access response in onResponse(Response respon

本文探讨了在使用OkHttp时遇到的一个常见问题:当尝试多次读取Response Body时出现的状态异常。具体表现为调用response.body().string()方法两次以上导致的Body被关闭的情况,并解释了只能调用该方法一次的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

okhttp onResponse(Response respon){}


java.lang.IllegalStateException: closed
	at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSource.
	read(HttpConnection.java:455)
	at okio.Buffer.writeAll(Buffer.java:594)
	at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:87)
	at com.squareup.okhttp.ResponseBody.bytes(ResponseBody.java:56)
	at com.squareup.okhttp.ResponseBody.string(ResponseBody.java:82)

原因:由于某处两次调用了
response.body().string();导致closed,有且只能调用一次

### WebMagic 中 `java.lang.IllegalStateException: stream has already been operated upon or closed` 的解决方案 在使用 WebMagic 进行网络爬虫开发时,可能会遇到类似于 `java.lang.IllegalStateException: stream has already been operated upon or closed` 的异常。这种错误通常发生在尝试多次读取同一个输入流或者该流已经被关闭的情况下。 #### 原因分析 当我们在处理 HTTP 请求返回的数据时,如果已经通过某种方式消费了响应体的内容(例如调用了 `.string()` 方法),那么底层的流就会被关闭。再次访问这个流会抛出上述异常[^2]。这与 OkHttp 或其他类似的库的行为一致[^3]。 #### 解决方案 为了避免此类问题的发生,可以通过以下几种方式进行优化: 1. **缓存响应数据** 将原始的响应内容保存到内存或磁盘中,在后续操作中直接使用这些缓存下来的数据而不是重新获取流对象。 ```java @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); Response originalResponse = chain.proceed(request); // 缓存响应体字符串形式 String responseBodyString = originalResponse.body().string(); MediaType contentType = originalResponse.body().contentType(); // 创建新的响应体并替换原响应体 ResponseBody newBody = ResponseBody.create(contentType, responseBodyString); return originalResponse.newBuilder() .body(newBody) .build(); } ``` 2. **只读一次流** 确保每次请求只会读取一次流,并将其转换成适合的形式存储起来供后续逻辑使用。这样可以有效防止重复读取带来的问题。 3. **调整框架配置** 对于某些特定场景下的需求,可能需要修改 WebMagic 的内部实现细节以适应项目实际状况。比如自定义下载器类来控制如何管理连接以及资源释放等问题。 4. **日志记录改进** 如果只是为了调试目的而打印整个 HTML 页面内容的话,建议仅截取部分内容而非全部输出,从而减少不必要的性能开销同时也降低了触发此 bug 的可能性。 以上方法都可以很好地规避掉因为不当操作而导致的 IllegalStateException 异常情况发生。 ```java // 示例代码片段展示如何安全地处理OkHttp响应 @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); try (Response response = chain.proceed(request)) { if (!response.isSuccessful()) throw new IOException("Unexpected code " + response); // 获取MediaType和字符编码信息 MediaType mediaType = response.body().contentType(); // 转化为字符串表示形式的同时保持原有结构不变 String content = response.body().string(); System.out.println("Response Content:" + content.substring(0, Math.min(content.length(), 50))); // 构建新副本以便继续传递给下游组件 return response.newBuilder() .body(ResponseBody.create(mediaType, content)) .build(); } } ``` ### 注意事项 - 在 Android 应用程序生命周期内合理管理对话框状态能够降低非法参数异常发生的几率[^4]。 - 当渲染 PDF 文件的第一页作为预览功能时,可采用挂起函数简化异步流程设计[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值