httpretryexception表示jdk内置重试已失败,应记录日志并降级处理,而非再次重试;它属受检异常,继承ioexception,多在getinputstream()等响应读取时抛出,语义明确且不可忽略。

网络请求异常在 Java 中不能一概而论地“捕获后重试”,关键要区分异常类型、明确语义、按需响应。HttpRetryException、IOException 子类、超时类异常、协议类异常等,各自代表不同层级的问题,处理方式差异明显。
区分受检异常与运行时异常
Java 强制你处理所有受检异常(如 IOException 及其子类 HttpRetryException、UnknownHostException、SocketTimeoutException),编译器会报错,不处理就过不了。这类异常必须显式 catch 或 throws。
- HttpRetryException:表示 JDK 内置重试已失败,不是让你再手动 retry,而是该记录日志、降级或返回默认值
- SocketTimeoutException / ConnectException:属于 IOException 子类,说明连接或读取阶段超时/中断,适合有限重试(需自定义逻辑,JDK 不自动重试)
- RuntimeException 类异常(如 NullPointerException):编译器不强制捕获,但暴露的是代码缺陷,应提前校验参数、避免空指针,而不是靠 try-catch 补救
正确捕获和响应网络异常
不要在 getInputStream() 或 getResponseCode() 之外提前 catch;异常往往延迟抛出——真正读响应时才暴露问题。推荐结构如下:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 try-with-resources 管理 HttpURLConnection 或流资源
- catch 块中优先捕获具体子类(如 HttpRetryException → SocketTimeoutException → IOException),避免父类吞掉子类
- 每个 catch 块必须有明确动作:记录带上下文的日志(如 URL、请求参数)、转换为业务异常(如 throw new ServiceException("调用支付网关失败", e))、或提供兜底值(如 return cachedResult)
- 禁用空 catch 和 e.printStackTrace() —— 生产环境日志不可查、无上下文、易掩盖严重错误(如 OutOfMemoryError)
超时与重试策略要分开设计
超时是配置项,重试是业务决策,二者不能混为一谈:
- JDK 的 HttpURLConnection 默认仅对部分底层错误(如 DNS 失败)做极简重试(最多 2 次),且不可配置;它不重试超时,也不重试 4xx/5xx 状态码
- 若需可控重试(如 3 次 + 指数退避),应封装在业务层,配合自定义拦截器或 RetryTemplate(Spring);重试前务必判断异常是否幂等(如 POST 不宜盲目重试)
- ConnectTimeout 和 ReadTimeout 需显式设置,否则可能卡死线程;建议设为 3~5 秒(连接)和 10~30 秒(读取),视服务 SLA 调整
HTTP 状态码异常需单独处理
200 以外的状态码(如 403、404、500)不会抛出异常,但需主动检查 responseCode 并处理:
- 401/403:认证或权限问题,应刷新 token 或提示用户登录,而非重试
- 404:资源不存在,重试无意义,可记录并返回空结果或默认值
- 5xx:服务端错误,适合有限重试(如 502/503),但需结合熔断(如 Hystrix/Sentinel)防雪崩
- 建议统一包装 HttpResponse,把状态码、body、headers 封装为 Result
,避免各处重复 if-else 判断
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










