欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.NET Core中使用HttpClient的正确姿势

程序员文章站 2023-11-12 23:31:34
前言 为了更方便在服务端调用 http 请求,微软在 .net framework 4.x 的时候引入了 httpclient。但 httpclient 有很多严重问题,...

前言

为了更方便在服务端调用 http 请求,微软在 .net framework 4.x 的时候引入了 httpclient。但 httpclient 有很多严重问题,一直饱受诟病,比如 infoq 的这篇文章 t.cn/evzy80y,吐槽了 httpclient 不能立即关闭连接、性能消耗严重等的问题。

http协议的重要性相信不用我多说了,httpclient相比传统jdk自带的urlconnection,增加了易用性和灵活性,它不仅是客户端发送http请求变得容易,而且也方便了开发人员测试接口(基于http协议的),即提高了开发的效率,也方便提高代码的健壮性。因此熟练掌握httpclient是很重要的必修内容,掌握httpclient后,相信对于http协议的了解会更加深入。

.net core 2.1 开始引入的 httpclientfactory 解决了 httpclient 的所有痛点。有了 httpclientfactory,我们不需要关心如何创建 httpclient,又如何释放它。通过它可以创建具有特定业务的 httpclient,而且可以很友好的和 di 容器结合使用,更为灵活。

下面以 asp.net core 为例介绍 httpclient 新的三种正确使用方式。

一、直接使用方式

不管是哪种方式,都要先注册服务,对于 asp.net core 应用则是在 startup.cs 文件的 configureservices 添加如果代码:

services.addhttpclient();

然后在 controller 中通过构造注入的试获得 ihttpclientfactory,然后通过它来创建 httpclient 对象。示例代码:

public class valuescontroller : basecontroller
{
 private readonly ihttpclientfactory _httpclientfactory;
 public valuescontroller(ihttpclientfactory httpclientfactory)
 {
  _httpclientfactory = httpclientfactory;
 }

 [httpget]
 public async task<actionresult> get()
 {
  var client = _httpclientfactory.createclient();
  client.baseaddress = new uri("http://api.github.com");
  string result = await client.getstringasync("/");
  return ok(result);
 }
}

这种使用方式适合一次性的 http 请求调用,弊端是如果多次都要请求 github 的接口,那就得写很多重复代码配置 httpclient。

二、命名式使用方式

命名式的使用方式可以解决第一种方式的问题,对于特定域名的 http 调用,可以只做一次配置,然后在多个地方通过名称拿到相同的 client 来使用。

首先在 startup.cs 注册服务的地方添加带有特定名称的 httpclient 服务,并添加需要的配置,如下示例:

services.addhttpclient();
services.addhttpclient("github", c =>
{
 c.baseaddress = new uri("https://api.github.com/");
 c.defaultrequestheaders.add("accept", "application/vnd.github.v3+json");
 c.defaultrequestheaders.add("user-agent", "httpclientfactory-sample");
});

注意这里添加了两次 addhttpclient,一次是没有命名的,一次是有命名的。在 controller 中的使用方式是:

public class valuescontroller : basecontroller
{
 private readonly ihttpclientfactory _httpclientfactory;

 public valuescontroller(ihttpclientfactory httpclientfactory)
 {
  _httpclientfactory = httpclientfactory;
 }

 [httpget]
 public async task<actionresult> get()
 {
  var client = _httpclientfactory.createclient("github");
  string result = await client.getstringasync("/");
  return ok(result);
 }
}

但如果使用很频繁,这种获取 client 的方式还是有一点麻烦。下面介绍第三种方式,可以在使用的时候方便一点,但配置要麻烦些。

三、类型化使用方式

类型化的使用方式可以预先把配置放到自定义的 httpclient 中,然后在需要的地方都过依赖注入直接拿到 httpclient 实例。

我们来看具体的例子,首先自定义一个 httclient 类,比如访问 github 接口的类可以这样定义:

public class githubclient
{
 public httpclient client { get; private set; }

 public githubclient(httpclient httpclient)
 {
  httpclient.baseaddress = new uri("https://api.github.com/");
  httpclient.defaultrequestheaders.add("accept", "application/vnd.github.v3+json");
  httpclient.defaultrequestheaders.add("user-agent", "httpclientfactory-sample");
  client = httpclient;
 }

 public async task<string> getdata()
 {
  return await _client.getstringasync("/");
 }
}

这里的 getdata 就是额外扩展的共用方法。使用前需要为这个类注册服务:

services.addhttpclient<githubclient>();

然后在需要的地方(比如 controller)中这样使用:

public class valuescontroller : basecontroller
{
 private readonly githubclient _githubclient;;

 public valuescontroller(githubclient githubclient)
 {
  _githubclient = githubclient;
 }

 [httpget]
 public async task<actionresult> get()
 {
  string result = await _githubclient.getdata();
  return ok(result);
 }
}

类型化的方式和命名式的方式相比,虽然在配置的时候会麻烦一点,但它有两个好处:一是不用通过名称字符串来获得 client,而是直接通过依赖注入获得具体的 client;二是可以在自定义的 httpclient 类中扩展共用的方法。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。