3. 网络连接错误:超时设置不合理、DNS解析异常、代理/防火墙拦截

网络连接这玩意儿,说简单也简单,说头疼是真头疼。我见过太多团队在SDK集成时卡在这一步,日志里就甩一句“Connection timeout”或者“Name or service not known”,然后就抓瞎了。实际上,90%的线上网络报错都能归到三个坑里:超时设得不对、DNS解析挂了、代理/防火墙把路堵死了。

咱们一个一个来拆。

3.1 超时设置不合理

现象:SDK初始化或数据上报时反复重试,最终抛出ConnectionTimeoutException。

为什么会这样?大部分SDK为了“稳定”,会提供默认超时时间——有的给5秒,有的给10秒。但你的服务部署在海外,或者用户网络本身就有高延迟,这个默认值根本不够用。我遇到过最离谱的案例:某家物流SDK默认连接超时设了2秒,结果他们在东南亚的客户几乎全部失败。

常见超时参数对比

参数名默认值(常见)建议范围说明
connectTimeout5000 ms8000 ~ 15000 msTCP握手阶段的等待时间
readTimeout10000 ms15000 ~ 30000 ms读取服务器响应数据的间隔等待
writeTimeout10000 ms15000 ~ 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。

排查步骤:

  1. 用curl / wget模拟SDK的请求,看能否正常返回
  2. 检查HTTPS_PROXY、HTTP_PROXY环境变量是否被无意识设置
  3. 要求网络运维放开SDK需要的域名和端口白名单
  4. 如果是证书问题,让运维导出企业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解析异常 代理/防火墙拦截 检查/调整超时参数 更换DNS / 集成HTTPDNS 关闭代理 / 添加白名单 验证连接是否恢复 成功 → 结束 失败 → 日志抓包 建议:失败后用Wireshark抓包,结合应用层日志定位具体哪个环节出错

上面这张图就是我的“三板斧”思路:遇到网络报错,先判断是超时、DNS还是代理防火墙。逐一排查后验证,还不通就抓包看底层数据。

说实话,这三个问题你只要按流程走一遍,80%的网络错误都能在半小时内解决。剩下的20%,多半是服务器端配置或者中间链路的问题,那就不是SDK集成的锅了。