2012年5月31日 星期四

改用 HttpClient 的理由

之前在寫 WPF、Silverlight 時若是要去某些 REST API 往往是用 HttpWebRequest
這次撰寫 Windows 8 Metro App 時很自然的把之前寫的 class 搬過來用…
卻發現在某些 REST API 取資料時發生怪異現像…

在 TRACE 後發現此次介接的某幾支 API 在 http header 部份並沒有 ContenLength
而 Win RT 上的 HttpWebResponse 若想取得長度必須由 header 此欄位查詢…
在 Silverlight 上反而沒這種問題…明顯同個類別不同平台實作也有差異…
ContentLength 這個數字在我先前寫的 class 中有著重要的角色…
因為我必須利用這個值初始化一個 ByteArray
再由 HttpWebResponse.GetResponseStream 中將 http response 讀出來…
當然可以改用動態配置的方式解決…但每次連線就更費時費空間了…

查看 MSDN 後發現 HttpClient 提供了 GetByteArray、GetString 等 Method
這些都可以直接拿到完整的 http response 不必自己從 Stream 讀出來…
比較之下 HttpClient 在 Post 資料時的寫法也遠比 HttpWebRequest 清爽多了…
不論 Post String、Stream、Multipart 都簡單直覺…便利用 HttpClient 進行了改寫…
以下是一個簡單的範例…例如登入某服務時利用 Multipart Post uid、pwd 欄位…

public async Task<String> GetMemberStatus()
{
    String strResult = "";

    Uri server = null;
    if (Uri.TryCreate("http://aaa.net.tw/", UriKind.Absolute, out server))
    {
        HttpMessageHandler handler = new HttpClientHandler();
        handler = new PlugInHandler(handler);
        HttpClient httpClient = new HttpClient(handler);
        httpClient.BaseAddress = server;

        String strURL = "Admin.php?action=Login";
        MultipartFormDataContent form = new MultipartFormDataContent();
        form.Add(new StringContent("Ascii"), "uid");
        form.Add(new StringContent("123456789"), "pwd");
       
        HttpResponseMessage response = await httpClient.PostAsync(strURL, form);
        if(response != null && response.StatusCode == HttpStatusCode.OK)
        {
            strResult = await response.Content.ReadAsStringAsync();
        }
    }

    return strResult;
}

private class PlugInHandler : MessageProcessingHandler
{
    public PlugInHandler(HttpMessageHandler innerHandler)
        : base(innerHandler)
    {
    }

    // Process the request before sending it
    protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Method == HttpMethod.Get)
        {
            request.Headers.Add("Custom-Header", "CustomRequestValue");
        }
        return request;
    }

    // Process the response before returning it to the user
    protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
    {
        if (response.RequestMessage.Method == HttpMethod.Get)
        {
            response.Headers.Add("Custom-Header", "CustomResponseValue");
        }
        return response;
    }
}

沒有留言:

張貼留言