[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 吧!