.Net 4.5中增加了一个新的System.Net.Http.HttpClient名字空间(在 System.Net.Http.dll 中),用于发送 HTTP 请求和接收 HTTP 响应。

基本操作

和以前的HttpWebRequest相比,HttpClient更加简洁,下面就是一个下载www.windows.com页面的示例:

    string uri = "http://www.windows.com/";
    HttpClient client = new HttpClient();
    string body = await client.GetStringAsync(uri);

它支持编码识别和对压缩的http流解压,省去了我们的不少代码。除GetStringAsync()之外,还有GetByteArrayAsync()GetStreamAsync()PostAsync ()DeleteAsync()等函数,非常好用。

HttpClient.GetStringAsync()是一个简化的函数,用这个函数的时候,我们看不到HttpResponse的相关信息,如果需要看到Http响应的信息,可以用如下标准方式:

    HttpResponseMessage response = await client.GetAsync(uri);
    response.EnsureSuccessStatusCode();
    string responseBody = await response.Content.ReadAsStringAsync();

自定义HttpHeader

前面的示例非常简单,但有时我们需要在发送Get请求时在HttpHeader中加入一些额外的信息,常见的的有Refer、Cookie及UserAgent等。这个时候我们就要用到HttpClientHandler了,具体方法如下:

  1. 首先自定义一个HttpClienHanlder类,重载SendAsync方法。

    string uri = "http://www.windows.com/";
    HttpClient client = new HttpClient();

    class MyHttpClienHanlder:HttpClientHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request.Headers.Referrer = new Uri("http://www.google.com/");
            request.Headers.Add("UserAgent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727)");

            return base.SendAsync(request, cancellationToken);
        }
    }

  1. HttpClient构造函数中加入自定义的HttpClienHanlder类。

    string uri = "http://www.windows.com/";
    HttpClient client = new HttpClient(new MyHttpClienHanlder());
    string body = await client.GetStringAsync(uri);

可见,HttpClienHanlder其实就是是一个常见的代理模式的设计,它在HttpClient.GetStringAsync()中加了一层封装,拦截了HttpClient的输入和输出,从而实现一些自定义的操作。

常见问题

HttpClient虽然非常简单易用,但并不意味着它任何时候都能照着我们期望的方式工作,常见问题(我这两天试用过程中遇到的)如下:

  1. 中文乱码

HttpClient.GetStringAsync()本身支持编码识别,但如果HttpResponse的HttpHeader中不含CharSet信息时,便采用默认编码方式进行字符串解码,它的默认编码方式是无法解析中文的,此时便会出现中文乱码。

一种常见的做法是:如果HttpHeader中不含CharSet信息时,采用GBK方式来解码。要实现这个功能的话,还是需要用到前面提到的HttpClientHandler

    class MyHttpClienHanlder:HttpClientHandler
    {
        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var rsponse = await base.SendAsync(request, cancellationToken);
            var contentType = rsponse.Content.Headers.ContentType;
            if (string.IsNullOrEmpty(contentType.CharSet))
            {
                contentType.CharSet = "GBK";
            }
            return rsponse;
        }
    }

当然,这么做仍然不是很完善,有的时候如果要更精确的话还需要从Html页面中获取charset信息,甚至通过相应的库函数进行编码猜测。这儿我写了一个稍微完善的版本:

 1     class HtmlTextHandler : HttpClientHandler
 2     {
 3         protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 4         {
 5             var response = await base.SendAsync(request, cancellationToken);
 6 
 7             var contentType = response.Content.Headers.ContentType;
 8             contentType.CharSet = await getCharSetAsync(response.Content);
 9 
10             return response;
11         }
12 
13         private async Task<string> getCharSetAsync(HttpContent httpContent)
14         {
15             var charset = httpContent.Headers.ContentType.CharSet;
16             if (!string.IsNullOrEmpty(charset))
17                 return charset;
18 
19             var content = await httpContent.ReadAsStringAsync();
20             var match = Regex.Match(content, @"charset=(?<charset>.+?)""", RegexOptions.IgnoreCase);
21             if (!match.Success)
22                 return charset;
23 
24             return match.Groups["charset"].Value;
25         }
26     }
View Code

相关文章:

  • 2022-01-26
  • 2021-05-26
  • 2021-12-11
  • 2021-09-06
  • 2022-12-23
  • 2021-09-15
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-08-21
  • 2021-05-16
  • 2022-01-08
  • 2021-10-21
相关资源
相似解决方案