zoukankan      html  css  js  c++  java
  • .Net 4.5中的HttpClient试用

    .Net 4.5中的HttpClient试用

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

    基本操作

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

    static async Task<string> GetData()
    {
        var httpClient = new HttpClient();
        return await httpClient.GetStringAsync("http://www.weather.com.cn/data/sk/101010100.html");
    }
            
            
    static  void Main(string[] args)
    {
        Console.WriteLine(GetData().Result);
        Console.ReadLine();
    }
    

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

    注意:HttpClient提供的函数基本都是异步的

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

    static async Task<string> GetData()
    {
        var httpClient = new HttpClient();
        var httpResponMassage=await httpClient.GetAsync("http://www.weather.com.cn/data/sk/101010100.html");
        //请求成功
        if (httpResponMassage.IsSuccessStatusCode)
        {
            return await httpResponMassage.Content.ReadAsStringAsync();
        }
        return null;
    }
    

    自定义HttpHeader

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

    1. 首先自定义一个HttpClienHanlder类,重载SendAsync方法。
    using System;
    using System.Net.Http;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        public class MyHttpClientHandler:HttpClientHandler
        {
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                //告诉请求的api地址我是来自百度的调整过来的请求
                request.Headers.Referrer=new Uri("http://www.baidu.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传入该自定义对象
    static async Task<string> GetData()
    {
        var client= new HttpClient(new MyHttpClientHandler());
        return await client.GetStringAsync("http://www.weather.com.cn/data/sk/101010100.html");
    }
    

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

    常见问题

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

    1. 中文乱码。

    一般发生这种情况是由于页面的charset没有设置为“utf-8”或“GBK”编码格式。
    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信息,甚至通过相应的库函数进行编码猜测。这儿我写了一个稍微完善的版本:

    class HtmlTextHandler : HttpClientHandler
        {
            protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                var response = await base.SendAsync(request, cancellationToken);
    
                var contentType = response.Content.Headers.ContentType;
                contentType.CharSet = await getCharSetAsync(response.Content);
    
                return response;
            }
    
            private async Task<string> getCharSetAsync(HttpContent httpContent)
            {
                var charset = httpContent.Headers.ContentType.CharSet;
                if (!string.IsNullOrEmpty(charset))
                    return charset;
    
                var content = await httpContent.ReadAsStringAsync();
                var match = Regex.Match(content, @"charset=(?<charset>.+?)""", RegexOptions.IgnoreCase);
                if (!match.Success)
                    return charset;
    
                return match.Groups["charset"].Value;
            }
        }
    
    1. 响应内容过长导致HttpRequestException。

    HttpClient有一个属性MaxResponseContentBufferSize,它表示的是读取响应内容时最大字节数缓冲区。它的默认值是64k,当页面内容很多,超过64k的时候,就会抛出一个HttpRequestException,导致Get失败。这个属性必须是个正整数,也就是说,它是不支持自适应的,这个非常令人费解,不知道MS为什么非要自己估算页面大小,在Get操作前支持为合适的值,这个是个不够好用的地方。

    我查了一下MSDN,目前对这个属性的说明比较少,不知道更改这个值的大小会影响什么地方。即使把他设置成int.Max貌似也不会有过多的内存占用。不过为了安全起见,还是把它设置在一个合理的范围吧,像我一般就把它设置为1m。(PS: 在最新的.Net 4.5 RC中,这个值已经更新成了int.MaxValue,希望RTM版不要恢复成64k,确实不够用)

    HttpClient client = new HttpClient() { MaxResponseContentBufferSize = 1024 * 1024 };
    

    最后提一个不是问题的问题:HttpClient全部都是异步方法,没有同步方法,如果要在同步函数中使用,必须通过Task.Wait()来等待任务完成,稍稍有些不便。

    阅读原文

  • 相关阅读:
    linux查看CPU和内存信息
    linux yum命令详解
    查看文件中关键字前后几行的内容
    vue.js+web storm安装及第一个vue.js
    android GPS: code should explicitly check to see if permission is available
    ASP.NET MVC Identity 使用自己的SQL Server数据库
    阿里云服务器,tomcat启动,一直卡在At least one JAR was scanned for TLDs yet contained no TLDs就不动了
    ASP.NET MVC4 MVC 当前上下文中不存在名称“Scripts”
    python 将windows字体中的汉字生成图片的方法
    Java android DES+Base64加密解密
  • 原文地址:https://www.cnblogs.com/ypfnet/p/6526474.html
Copyright © 2011-2022 走看看