發如今家里的時候用Android App里的WebView打開站點非常慢,會有十幾秒甚至更長時間的卡住。
可是在電腦上打開相同的網頁卻非常快。
查找這個問題的過程比較曲折,記錄下來。
抓取Android網絡數據
為了調試這個問題,首先要抓取Android的網絡包數據。開始時,是想用Wireshark來抓包的,可是非常麻煩,tcpdump在手機要root權限。
於是轉換思路,能不能在Android上設置代理,來抓包?
可是fiddler沒有linux版本號,於是轉用BurpSuite了。
設置Android代理方法:
在Android網絡設置里,長按連接,選擇“改動網絡”,“顯示高級選項”,“代理”,“手動”,然后填上相應的代理的地址。
hosts和路由器配置的坑
抓取到http請求數據,發現訪問非常快,比在手機上快多了。說明並非網絡問題。
再細致觀察,發現了這個請求:
GET /gngo.js HTTP/1.1
Host: x.adpro.cn
回憶起來,這個是曾經屏蔽電信在網頁上插入的流氓廣告時配置了hosts:
127.0.0.1 adpro.cn
127.0.0.1 x.adpro.cn
於是在電腦上把這兩個hosts凝視掉之后,發現速度變慢了一點,可是不會像手機上那樣卡十幾秒。
再嘗試在電腦上的瀏覽器打開http://x.adpro.cn/gngo.js,發現打不開。
ping x.adpro.cn
發現返回的結果是127.0.0.1
為什么在hosts文件中把 x.adpro.cn的條目凝視掉了,返回的結果還是127.0.0.1?
折騰了一陣子,嘗試各種清除linux dns的方法,發現x.adpro.cn的解析結果還是127.0.0.1。
再次想起,曾經在路由器上配置過防火牆,果然例如以下有配置了對adpro.cn的攔截:

在路由器里把這個規則失效之后,果然ping x.adpro.cn能返回正確的IP了。
原來是路由器把dns相關的請求也攔截了,導致linux取不到新的dns解析結果,一直用的都是舊的結果,所以總是把x.adpro.cn解析為127.0.0.1。
搞清楚緣由之后,又一次在路由器里攔截adpro.cn的數據包,然后又一次載入網頁,發現http://x.adpro.cn/gngo.js的請求會在十幾秒之后超時:

這就是在手機上為什么打開網頁要十幾秒的原因了:
路由器把adpro.cn的數據包攔截了,從而socket全然沒有數據返回,所以http請求在十幾秒后超時,Android WebView才渲染顯示出頁面。
為什么電腦上非常快?由於配置了127.0.0.1 x.adpro.cn,所以http請求直接返回失敗了,不會堵塞住。
很影響體驗的運營商廣告
在路由器上把攔截去掉,再在手機上訪問,又出現了一個坑爹的事情:
在WebWiew上會顯示電信插入的流氓廣告,把大部分區域都擋住了。

怎樣過濾掉運營商的流氓廣告?黑名單還是白名單
假設只是濾掉的話,用戶還以后是站點自己彈的廣告。那么怎樣在App里過濾掉這些流氓廣告?
在WebView里過濾某些url:
當url里含有廣告地址時,直接返回一個空的回應。
http://developer.android.com/reference/android/webkit/WebViewClient.html#shouldInterceptRequest(android.webkit.WebView, java.lang.String) http://developer.android.com/reference/android/webkit/WebViewClient.html#shouldInterceptRequest(android.webkit.WebView, java.lang.String)
webView.setWebViewClient(new WebViewClient() {
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
if (url.contains("adpro.cn")) {
return new WebResourceResponse(null, null, null);
}
return null;
}
注意的是在api level 11上才干夠重載上面的函數。
運營商的廣告域名都是相對固定的,能夠用黑名單來排除掉。
當然,假設自己的服務都是在自己的域名下的,那么能夠考慮採用白名單機制。
白名單機制另一個額外的優點,能夠算是一個有一定效果的防止XSS的方法了。
其他的一些東東:
Android上抓包的一些文章:
http://www.trinea.cn/android/android-network-sniffer/ Android利用Fiddler進行網絡數據抓包
http://www.freebuf.com/articles/wireless/6517.html 實時抓取移動設備上的通信包(ADVsock2pipe+Wireshark+nc+tcpdump)
