[WinRT] WinRT 世界中三種 Http class (System.Net.HttpWebRequest, System.Net.Http.HttpClient, Windows.Web.Http.HttpClient) 下載行為差異

WinRT 世界中三種 Http class 的兩三事

  1. System.Net.HttpWebRequest
  2. System.Net.Http.HttpClient
  3. Windows.Web.Http.HttpClient

在 desktop .NET 的話,應該是只有前兩種,第三種是在 WinRT 下面才會出現的
所以這篇主要針對在 WinRT 下三種 http class 的行為
因為在 desktop .NET 雖然前兩者是共通的,但行為上可能還是不一樣

原本是想要找出在手機低速的時候下載檔案的問題,然後利用了 Charles Proxy 這套軟體去觀察下面這幾個用 Http 下載東西的情況

  1. System.Net.HttpWebRequest
  2. System.Net.Http.HttpClient
  3. 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 吧!