WinRT 世界中三種 Http class 的兩三事
- System.Net.HttpWebRequest
- System.Net.Http.HttpClient
- Windows.Web.Http.HttpClient
在 desktop .NET 的話,應該是只有前兩種,第三種是在 WinRT 下面才會出現的
所以這篇主要針對在 WinRT 下三種 http class 的行為
因為在 desktop .NET 雖然前兩者是共通的,但行為上可能還是不一樣
原本是想要找出在手機低速的時候下載檔案的問題,然後利用了 Charles Proxy 這套軟體去觀察下面這幾個用 Http 下載東西的情況
- System.Net.HttpWebRequest
- System.Net.Http.HttpClient
- Windows.Web.Http.HttpClient
才發現一個很有趣的雷…
直接講結論,從 Charles Proxy 的觀察,下載的狀況分為兩種:(假設讀取的 Buffer 開 4096 bytes,實際上不管多大都一樣)
- 1 & 2 的狀況是相同的:不管是用 HttpResponse.GetResponseStream() 或者 HttpResponseMessage.Content.ReadAsStreamAsync() 取得的 Stream,在呼叫第一次的 Stream.Read 的時候,你會發現在 Charles Proxy 中會真的把 Content 下載完成後, 才真的會開始 Read 到東西,意思就是你跑 Debug 中斷在 Read ,然後按下 F10 (Step Over) 後,你會看到 Content 下載完,然後才會跳到下一行
- 3 的狀況:用 Windows 這個 namespace 下的 HttpResponseMessage 要讀取 Stream,必須要先呼叫 HttpResponseMessage.Content.ReadAsInputStreamAsync() 取得 IInputStream 然後可以透過 AsStreamForRead() 這個extension method 去把 IInputStream 轉換成 Stream,而 AsStreamForRead 這個 method 可以指定 buffer size,此時把 size 給 0 的話,你就可以發現下載的狀況是跟 Charles Proxy 中觀察到的是同步的,也就是第一次呼叫 Stream.Read 的時候,他就真的會讀到多少就會馬上跳到下一行,就不會像 1 & 2 的狀況會先把整個東西下載完才會動
之前看有人說 HttpClient 的底層是用 HttpWebRequest 做的,我想這邊指的 HttpClient 是 System.Net.Http.HttpClient 而非 Windows.Web.Http.HttpClient,用到這邊才發現為什麼官方有宣導要我們用 Windows 這個 namespace 下的 HttpClient 而非其他兩者
但上述的狀況僅針對 Windows Phone 8.1 ,其他平台也許因為底層 implement 的不同而有不同的狀況,但我想對於不管是 8.1 (Windows / Windows Phone) 或 Windows 10 之後的 UWP ,就盡量使用 Windows namespace 之下的 HttpClient 吧!