批量请求中多次读取Google Client响应内容的重试问题
解决Google Drive API响应流耗尽导致的解析异常问题
这个问题我太有共鸣了——Google Client的HttpResponse输入流默认是一次性的,一旦你调用parseAs()或者直接读取内容,后续框架再尝试解析时就会因为流空掉抛出异常。核心解决方案就是让响应流支持重复读取,下面给你两种实用的实现方式:
方案1:手动缓存响应内容(兼容所有版本)
先把响应内容读取到字节数组里,再重新包装成可重复读取的ByteArrayInputStream,这样不管是你的错误判断逻辑还是后续的Google Client解析,都能拿到完整的内容。
步骤1:添加缓存工具方法
private byte[] cacheResponseContent(com.google.api.client.http.HttpResponse response) throws IOException { InputStream originalStream = response.getContent(); ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int bytesRead; // 读取原始流到字节数组 while ((bytesRead = originalStream.read(buffer)) != -1) { byteStream.write(buffer, 0, bytesRead); } byteStream.close(); byte[] contentBytes = byteStream.toByteArray(); // 将响应流替换为可重复读取的ByteArrayInputStream response.setContent(new ByteArrayInputStream(contentBytes)); return contentBytes; }
步骤2:修改错误判断方法
private boolean isRateLimitExceeded(com.google.api.client.http.HttpResponse response) throws IOException { int statusCode = response.getStatusCode(); if (statusCode == 403) { // 先缓存内容,确保流可重复读取 byte[] contentBytes = cacheResponseContent(response); // 使用缓存的字节数组解析错误信息,不影响原始流 GoogleJsonErrorContainer jsonResponse = Utils.getDefaultJsonFactory() .createJsonObjectParser() .parseAndClose(new ByteArrayInputStream(contentBytes), Charset.defaultCharset(), GoogleJsonErrorContainer.class); List<ErrorInfo> errors = jsonResponse.getError().getErrors(); if (errors != null && !errors.isEmpty()) { List<String> recoverableErrors = Arrays.asList( "limitExceeded", "concurrentLimitExceeded", "rateLimitExceeded", "userRateLimitExceeded", "servingLimitExceeded" ); for (ErrorInfo errorInfo : errors) { if (!recoverableErrors.contains(errorInfo.getReason())) { return false; } } return true; } } return false; }
方案2:使用Google Client自带的缓存方法(简洁版)
如果你的google-api-client版本在1.32.0及以上,可以直接用框架自带的buffer()方法,它会自动把响应内容缓存到内存中,让流支持重复读取:
private boolean isRateLimitExceeded(com.google.api.client.http.HttpResponse response) throws IOException { int statusCode = response.getStatusCode(); if (statusCode == 403) { // 调用buffer()缓存内容,让流可重复读取 response.buffer(); response.getRequest().setParser(Utils.getDefaultJsonFactory().createJsonObjectParser()); GoogleJsonErrorContainer jsonResponse = response.parseAs(GoogleJsonErrorContainer.class); List<ErrorInfo> errors = jsonResponse.getError().getErrors(); if (errors != null && !errors.isEmpty()) { List<String> recoverableErrors = Arrays.asList( "limitExceeded", "concurrentLimitExceeded", "rateLimitExceeded", "userRateLimitExceeded", "servingLimitExceeded" ); for (ErrorInfo errorInfo : errors) { if (!recoverableErrors.contains(errorInfo.getReason())) { return false; } } return true; } } return false; }
注意事项
- Google API的错误响应体积通常很小,缓存到内存不会有性能问题;如果处理大体积响应,你可以考虑临时文件缓存,但一般没必要。
- 一定要在任何读取流的操作之前执行缓存逻辑,否则会导致内容不完整。
- 缓存过程中可能抛出
IOException,建议捕获后视为不可恢复错误,避免无限重试。
内容的提问来源于stack exchange,提问作者gbaso
相关产品推荐
相关产品推荐

