API25及以上版本连接REST Service时遇IOException求助
排查REST API读取IOException问题(API25+)
我之前帮同事排查过几乎一模一样的问题,结合你描述的conn.getInputStream()抛异常、isConnected返回false的情况,咱们从代码逻辑、系统配置和网络环境三个维度来拆解:
一、先排查代码层面的常见坑
1. 绝对不能在主线程发起网络请求
API25之后Android严格禁止在主线程执行网络操作,哪怕你没直接看到NetworkOnMainThreadException,也可能间接触发IOException(因为主线程网络请求会被系统强制中断)。
解决办法:把请求放到子线程,比如用AsyncTask(API25完全可用)、Coroutine或者RxJava:
// 示例:用AsyncTask做网络请求 new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... voids) { String result = ""; try { URL url = new URL("你的API地址"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); // 先打印响应码,排查服务器端问题 int responseCode = conn.getResponseCode(); Log.d("API_DEBUG", "响应码: " + responseCode); if (responseCode == HttpURLConnection.HTTP_OK) { InputStream inputStream = conn.getInputStream(); result = new Scanner(inputStream, "UTF-8").useDelimiter("\\A").next(); inputStream.close(); } else { // 读取错误流,获取服务器返回的错误信息 InputStream errorStream = conn.getErrorStream(); String errorMsg = new Scanner(errorStream, "UTF-8").useDelimiter("\\A").next(); Log.e("API_ERROR", "错误信息: " + errorMsg); } conn.disconnect(); } catch (IOException e) { e.printStackTrace(); } return result; } @Override protected void onPostExecute(String s) { super.onPostExecute(s); Log.d("JSON_RESULT", s); } }.execute();
2. 检查连接配置是否完整
- 确认请求方法是否正确(比如API要求POST,你用了GET)
- 设置合理的超时时间(避免因超时触发IOException)
- 如果API需要请求头(比如
Content-Type、Authorization),一定要加上:
conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Authorization", "Bearer 你的token");
3. 优先用getResponseCode()排查问题
不要直接抓getInputStream()的异常,先调用conn.getResponseCode():
- 如果返回4xx/5xx,说明服务器端有问题,用
conn.getErrorStream()读取错误详情 - 如果返回200再去读输入流,能帮你快速定位是网络问题还是服务器问题
二、系统配置必须到位(API25+的特殊要求)
1. 网络权限不能少
在AndroidManifest.xml里必须添加:
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
INTERNET是正常权限,不需要动态申请;ACCESS_NETWORK_STATE用来判断设备是否真的联网。
2. 明文HTTP请求的限制(API28+默认禁止)
如果你的API是HTTP协议(不是HTTPS),API28之后默认会拦截明文请求,触发IOException。解决办法:
- 在
res/xml下创建network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <!-- 允许所有明文请求(测试用,上线建议只允许指定域名) --> <base-config cleartextTrafficPermitted="true"/> <!-- 或者只允许特定域名的明文请求 --> <!-- <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">your-api-domain.com</domain> </domain-config> --> </network-security-config>
- 在
AndroidManifest.xml的application标签里引用:
<application ... android:networkSecurityConfig="@xml/network_security_config">
3. HTTPS证书问题(如果API是HTTPS)
如果API用的是自签名证书或者无效证书,会触发SSLHandshakeException(属于IOException的子类)。需要在代码里配置信任该证书,或者让服务器更换有效证书。
三、网络环境排查(你怀疑的防火墙问题)
1. 先确认设备真的联网
用代码判断当前网络状态:
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); Log.d("NETWORK_CHECK", "设备是否联网: " + isConnected);
如果这里返回false,说明设备本身没联网,和API无关。
2. 排除防火墙/代理干扰
- 切换网络:比如从公司WiFi换成手机流量,测试是否能连接API
- 用ping命令测试API域名:在电脑终端执行
ping your-api-domain.com,看是否能通 - 检查设备是否设置了代理:如果有代理,可能导致无法连接API
最后总结排查步骤
- 先用Postman/浏览器访问API,确认API本身能正常返回JSON
- 把网络请求移到子线程,避免主线程限制
- 检查Manifest权限和网络安全配置
- 打印响应码和错误流,定位具体异常原因
- 切换网络测试,排除防火墙/代理问题
内容的提问来源于stack exchange,提问作者Luke676
相关产品推荐
相关产品推荐

