httpclient 连接池工具类_DotNet应用之爬虫入门系列(二):HttpClient的前世今生

450723f3654ea7e63f98a82c2187c035.png

接上期《DotNet应用之爬虫入门系列(一):从.Net走进爬虫世界》。

对想写网页爬虫的人来说,最先要搞清楚的基础知识就是HTTP/HTTPS,以及所使用的编程语言对应该领域的基础库。因此,本文将为有兴趣的读者介绍.Net基础库中涉及HTTP的基础部分,并展示一些简单易懂的示例(同时,我计划在下期或下下期提供一个稍有难度、较为完整的爬虫案例,让新手更深刻地理解.Net库对HTTP的封装,以及如何处理编写爬虫过程中的意外情况)。另外须提示的是,看懂本文起码需要知道Http相关的“概念性”基础知识,例如知道GET、POST方法是什么,Http请求的Headers通常有哪些及分别表示什么等等;一些案例如果自己想尝试和复现,需要知道浏览器调试抓包工具使用方面的知识(这些资料网上非常丰富,笔者不再赘叙,浏览器建议选择谷歌或火狐,抓包工具有Windows适用的Fiddler或Mac上常用的Charles)。

前世的HttpWebRequest/HttpWebResponse

早先使用C#编写一个Http请求,需要用到System.Net.HttpWebRequest类。这个类的设计可谓非常之原始,但这也意味着它非常贴合编写Http请求的需要。

f6be27ffa3df6a521a2bbb3948621289.png
HttpWebRequest APIs from .Net Core 2.2

让我们借一个很简单的例子来看看编写出的代码。简书,是一个非常简洁、别致的创作社区(知乎别吃醋哦)。在它的首页上,有一个“推荐作者”的区域(已用红色方框标注),如图:

abd197bfb686e80c77554b272eec42ef.png
简书首页(2019.08.18)

通过浏览器调试可以很轻松地发现,这个区域的数据是通过一个请求单独获取的:

49ec0f76df422db7e52042bff2515200.png

那么,我们按部就班地向HttpWebRequest实例填入网站所需的请求参数,就可以获得我们想要的响应文本。控制台代码如下:

HttpWebRequest 

运行代码后就可以在控制台程序上打印出响应文本(很明显,这是一个Json格式的文本):

93bcd3e9b69abbee8ef76d75fe0138d5.png
“推荐作者”响应文本

让我们回头看一下这段代码。如果读者对Http有了基础性认识的话,应该会觉得这样的代码很亲切,无非就是复制粘贴,依次给类里的属性赋值即可。这是抽象层次低的好处,非常方便理解。但这也意味着使用者要注意的地方变多了,例如:

  • Method属性是一个String类型,如果不小心写错了,就会触发异常。
  • GetResponse()方法返回的是一个父类——WebResponse类,每次都需要通过类型转换变成HttpWebResponse对象。
  • 输出文本并没有相应的API,只能先通过HttpWebResponse对象的GetResponseStream()方法获取Stream,然后通过StreamReader读取出文本。
  • 示例代码未启用Cookie参数,如果启用,需要自己创建并维护一个CookieContainer。
  • 包含很多不常用的属性和配置,显得臃肿、复杂。

这还只是单纯代码层面而言。如果是严肃的项目代码,还需要注意性能方面的问题,例如:

  • 单个HttpWebRequest默认只支持2个线程(.Net遵循了“Http协议规定,同个Http请求的并发连接数最大为2”),多线程环境下需要通过设置ServicePointManager类的DefaultConnectionLimit属性来解决(对代码的焦点产生了干扰)。
  • 每个请求都需要创建一个HttpWebRequest对象,过多的对象会导致资源来不及释放直至端口耗尽。
  • 一些特殊场景下的性能问题(比如HttpWebRequest.GetRequestStreamAsync doesn't open the connection to the server - we always buffer the content #11873)。

以及代码之外的现实问题,例如:

  • .Net Framework和.Net Core的实现不太一样了,可能会导致行为上有不同的结果(事实是,Github上.Net Core库有不少与此相关的issues,比如HttpWebResponse.Cookies different behavior in .net framework and .net core #33122)。
  • 官方文档网站Docs明确表示了“不建议使用HttpWebRequest进行新的开发”。

7a126784fab8aca1d72fdaccfc6dec1b.png
来自官方文档的注解

可以说,对于.Net Core项目,HttpWebRequest/HttpWebResponse已经成为了“历史遗产”。

f10ee86e6be3164e1337b799c9b90bcf.png
微软工程师如是说

不过,官方也是有两手准备:Avoid creating a new HttpClient per HttpWebRequest in some cases #15460。未来可能会在.Net5(其实就是.Net Core 4.0,微软改名部又发功了)又有一些优化工作。当然,作为一个新手来说,我们并不需要了解得那么详细,以上只是为了说明:HttpWebRequest/HttpWebResponse的设计,作为一个基础类库来说,它仅仅满足了让你“能用”,却还是“用起来不太舒服”。

今生的HttpClient

伴随着时代发展,.Net重新整合设计了System.Net.Http.HttpClient(Java程序猿可能有话说:“这不是跟Java抄的嘛!”嗯……名字的确是一样)。那么HttpClient又变成什么样子了呢?

fb419df23a93d6b9cdcd06ea1f9cbd40.png
HttpClient APIs from .Net Core 2.2

对比一下“前世”,我们惊喜地发现HttpClient的API似乎更精简了。它自带了常用的Http请求方法,比如获取百度首页,我们现在可以写成短短几行代码:

using 

结合上图,可以先简单总结几点改进:

  • HttpClient使用自带的GetStringAsync()方法就可以获取到响应文本,相应地还有GetStreamAsync()方法和GetAsync()方法,由浅入深,应有尽有,可以充分满足不同场景的需求。
  • 同时很明显的是,HttpClient的APIs全部是异步方法(且是线程安全的),这意味着HttpClient天生就是为高并发场景而设计。
  • 原本HttpWebRequest臃肿的各种属性,现在分散到HttpMessageHandler/HttpRequestMessage/HttpResponseMessage/HttpContent中了,虽然对编程新手来说抽象的提高意味着更高的学习成本,但一旦理解就会发现这样的设计使得代码更精简易读、逻辑焦点更突出。

现在我们尝试加入代理:

var 

可以看到我们不需要去修改请求参数赋值的代码块,而是引入一个HttpMessageHandler的子类SocketsHttpHandler,替换HttpClient的重载构造方法即可。如果我们要存储Cookie呢?只需要将UseCookie设为true即可——HttpClient在绝大多数情况下不需要手动维护Cookie。

现在让我们重写上面简书的例子:

using 

是否感觉这样的代码,结构层次更强,逻辑的焦点更明确?

还有,我们经常会遇到一些类似翻页的情况,还是以简书首页的“推荐作者”为例:

59d642aff850578b76f40a8c6c058963.png
简书“推荐作者”

当我们点击换一批时,会发现请求变成了:

26dceb4bbe2f6ad048773ce37a3c164b.png
“换一批”

seen_ids记录了我们看过的推荐作者id,所以我们需要之前所有请求得到的作者id,拼成新的URL再做新的请求。如果使用HttpWebRequest,那么每次都要生成新的对象,并为它赋值后再请求。而HttpClient推荐的用法是尽量使用单例,而此案例只需使用1个HttpClient,就足够满足我们的需求。参考上面注释区域的代码,我们只需要每次生成一个极轻量的HttpRequestMessage,通过SendAsync()方法依次请求即可,最大程度地复用了HttpClient的DefaultRequestHeaders部分。我想从这一点,就足以令读者发现分离设计的好处。

HttpClient的发展之路还远远没有结束,它还在不断地被.Net社区讨论和优化。关于HttpClient更多的详细信息,可以阅读官方文档的“注解”:

HttpClient Class (System.Net.Http)​docs.microsoft.com
d690ebf40f9e27bdc1973a9a1d212b29.png

小结

笔者仅以此文向读者粗略介绍了.Net上Http基础库的基本用法——是的,以上还只是“粗略”、“基本”——但是起码我们可以写一些像样的爬虫了。爬到了数据,我们就可以尝试挖掘数据的价值,就可以像有些文章作者一样,贴出各种好看的图表来炫耀自己的所得了。希望这种获得和挖掘的乐趣能够不断驱动着读者们的技术人生,让我们下期再会!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值