背景:在开发应用的时候,出现了一个奇怪的现象,就是华为的部分机型,在移动4G CMNET的情况下,无法连接网络,经过对于这个问题的研究和解决,才引发了这篇博客的思考与学习,在这里与大家分享。
测试case:(华为meta 8,meta 7,P8,P9的6.0机器才有这个问题)
| 移动4G(CMNET) | 移动4G(CMWAP) | 电信 | 联通 | WiFi |
我们应用的域名A | ✖ | ✓ | ✓ | ✓ | ✓ |
我们应用的其他域名 | ✓ | ✓ | ✓ | ✓ | ✓ |
(还有一个case就是 上海的移动4G可以,但是北京和天津的不可以)
各位看了上面的case,第一反应应该就是移动运行商或者是我们自己域名的服务器的问题。
问题出现了,服务器是收到了我们的请求,并且也是已经返回消息的,但是客户端就是一只timeout。
综合上面的分析,
我想到的
第一个想法就是抓去tcp ip包进行分析,结果此路不通。(原因是复现的机器都是6.0的,而且根本就root不了)
第二个想法就是能否通过代理抓包,结果是移动卡复现,没有root,这条路也不行。
就在山穷水尽的时候,我和另一位同事,同时通过自己写demo进行客户端网络请求,结果他的是可以的,我写的demo就不可以。
于是乎我觉得和客户端写的代码逻辑有关。
我就将所有的网络请求框架每个写一个demo,这种东西网络一找一大堆,随便找了一个改一下,就可以用了,基本上没有什么时间消耗。
测试结果如下:
URLConnection | java.net.ProtocolException: unexpected end of stream |
HttpURLConnection | java.net.ProtocolException: unexpected end of stream |
HttpClient | ok |
volley | TimeOut |
AbstractHttpClient/DefaultHttpClient | TimeOut |
OkHttpClient | Ok |
这样感觉有点头目了,大不了,将我们之前用的volley网络框架完全改为另外两种可以运行的网络框架就ok了,但是这种代价貌似有点大啊,
我们先有一种最小的改动解决问题的方案,
这是就需要截取包,进行对比了,虽然移动网络下不行,但是wifi和移动我们发出的请求肯定都是相同的。
抓去结果如下:
使用OKHttp截包效果如下:
使用volley截包效果如下:
经过与另外几种访问网络请求对比之后,发现可以的请求,使用的都是自己的User-Agent,不能访问网络的请求的Agent都是使用华为的Agent,
所以我怀疑和Agent有关,所以将volley的包的User-Agent修改为其他的Agent
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = super.getHeaders();
if(headers.size() == 0){
<span style="white-space:pre"> </span>headers = new HashMap<>();
<span style="white-space:pre"> </span>headers.put("User-Agent", "okhttp/2.5.0");
}
return headers;
}
结果就可以了,真是突入其来的惊喜。
好了,结局方案有了,最起码是可以解决的。
下面还需要继续来分析为什么?
因为的理解这个agent是统计谁请求的,是浏览器,还是某个客户端,理论上应该没有影响啊,所以我们需要服务器端的帮助。
结果分析,发现,服务器端如果直接访问ip就是可以使用的,而且及时访问域名,也是有一定概率可以使用的。只是timeout的时间需要设置的很大,
所以觉得可能和服务器的某些机器有关系,本来打算在服务器端抓包来处理的,但是一指定到某个机器的ip的时候,就可以使用了,又断线了,
考虑到两方面因素:1.客户端可以修复了,而且热补丁可以快速的解决问题
2.这个事情的排查太耗时了,项目还比较紧张,
所以就没有继续往下跟踪分析。
这个等有时间,我还会继续查找相关资料来分析问题的根本原因。
目前就只能这样了,
这里贡献一下我的多种网络请求访问的demo:https://github.com/xiepengchong/NetworkDemo
我也是在网上查找,修改获取的,取之于网,馈之予网。