3. 网络连接错误:超时设置不合理、DNS解析异常、代理/防火墙拦截
网络连接这玩意儿,说简单也简单,说头疼是真头疼。我见过太多团队在SDK集成时卡在这一步,日志里就甩一句“Connection timeout”或者“Name or service not known”,然后就抓瞎了。实际上,90%的线上网络报错都能归到三个坑里:超时设得不对、DNS解析挂了、代理/防火墙把路堵死了。
咱们一个一个来拆。
3.1 超时设置不合理
现象:SDK初始化或数据上报时反复重试,最终抛出ConnectionTimeoutException。
为什么会这样?大部分SDK为了“稳定”,会提供默认超时时间——有的给5秒,有的给10秒。但你的服务部署在海外,或者用户网络本身就有高延迟,这个默认值根本不够用。我遇到过最离谱的案例:某家物流SDK默认连接超时设了2秒,结果他们在东南亚的客户几乎全部失败。
常见超时参数对比
| 参数名 | 默认值(常见) | 建议范围 | 说明 |
|---|---|---|---|
connectTimeout | 5000 ms | 8000 ~ 15000 ms | TCP握手阶段的等待时间 |
readTimeout | 10000 ms | 15000 ~ 30000 ms | 读取服务器响应数据的间隔等待 |
writeTimeout | 10000 ms | 15000 ~ 30000 ms | 写入请求体的间隔等待(OkHttp等库特有) |
我个人的习惯:把connectTimeout初始设为12秒,再根据线上P99延迟动态调优。千万别一上来就用默认值——你以为SDK帮你省事,其实它在帮你挖坑。
改超时配置的代码示例:
// 以 OkHttp 为例
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(12, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build();
注意:超时设得太大也不行。比如设成60秒,用户网络一断,SDK就会在那干等一分钟,体验极差。要结合业务场景设一个合理的上限——我通常不超过30秒。
3.2 DNS解析异常
现象:日志中出现UnknownHostException,或者Unable to resolve host "xxx.com"。
DNS这事,说白了就是“你给了一个域名,系统找不到对应的IP”。原因很多:
- 本地DNS缓存了过期记录
- 运营商DNS污染或劫持
- 使用了不稳定的公共DNS(比如偶尔抽风的114)
- IPv6/IPv4双栈环境下解析策略出错
我曾经调过一个支付SDK,用户在某个省份老是报DNS解析失败,排查到最后发现是当地运营商把阿里云的DNS服务器给“优化”了——其实就是直接丢包。最后我们换成了HTTPDNS方案,问题才彻底解决。
推荐的做法是不要依赖系统默认DNS,直接集成HTTPDNS SDK(各大云厂商都有)。示例:
// 使用阿里云 HTTPDNS 示例(伪代码)
HttpDnsService httpdns = HttpDns.getService(context, "yourAccountId");
String ip = httpdns.getIpByHostAsync("api.example.com");
if (ip != null) {
// 直接用IP发起请求,跳过系统DNS解析
URL url = new URL("https://" + ip + "/path");
// 别忘了设置Host头
connection.setRequestProperty("Host", "api.example.com");
}
如果不想引入HTTPDNS,也可以在程序启动时主动做一次InetAddress.getByName("域名"),把结果缓存到本地,出现解析失败时降级到备用IP列表。
3.3 代理/防火墙拦截
现象:能ping通外网,但SDK始终连不上目标服务器;或者只有WiFi下失败,4G下正常。
你看,很多企业的办公网络会设置透明代理或HTTPS拦截(比如用公司证书做中间人解密)。SDK如果固定写了证书校验,又不信任企业的根证书,直接报SSLHandshakeException。还有的防火墙会拦截非标准端口——我见过强行拦8443端口的,只放行443。
排查步骤:
- 用curl / wget模拟SDK的请求,看能否正常返回
- 检查
HTTPS_PROXY、HTTP_PROXY环境变量是否被无意识设置 - 要求网络运维放开SDK需要的域名和端口白名单
- 如果是证书问题,让运维导出企业CA证书,集成到SDK的自定义TrustManager中
千万别为了省事直接把SSL校验全部关闭。我曾经见过有人写trustAll(),结果被安全审核怼回来重写全流程,还背了绩效扣分。安全底线不能碰。
代理绕过代码片段:
// 如果系统设置了代理,OkHttp 会自动使用。手动绕过的姿势:
OkHttpClient client = new OkHttpClient.Builder()
.proxy(Proxy.NO_PROXY) // 直连,不走系统代理
.build();
// 或者指定使用某个代理:
// .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.company.com", 8080)))
下面我把整个排查链路整理成一张流程图,方便你对照操作。
上面这张图就是我的“三板斧”思路:遇到网络报错,先判断是超时、DNS还是代理防火墙。逐一排查后验证,还不通就抓包看底层数据。
说实话,这三个问题你只要按流程走一遍,80%的网络错误都能在半小时内解决。剩下的20%,多半是服务器端配置或者中间链路的问题,那就不是SDK集成的锅了。