在.net core中使用HttpClient请求api,有很多资源的问题,比如使用using的时候,虽然可以释放资源,但是套接字(socket)也不会立即释放,所以.net core2.1中,新增了IHttpClientFactory.将其用于配置和创建应用中的 HttpClient 实例。 这能带来以下好处:
- 提供一个中心位置,用于命名和配置逻辑
HttpClient
实例。 例如,可注册和配置 github 客户端,使其访问 GitHub。 可以注册一个默认客户端用于其他用途。 - 通过委托
HttpClient
中的处理程序整理出站中间件的概念,并提供适用于基于 Polly 的中间件的扩展来利用概念。 - 管理基础
HttpClientMessageHandler
实例的池和生存期,避免在手动管理HttpClient
生存期时出现常见的 DNS 问题。 - (通过
ILogger
)添加可配置的记录体验,以处理工厂创建的客户端发送的所有请求。
一、基本用法
在 Startup中的ConfigureServices中
services.AddHttpClient();
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using WebApplication1.Content; namespace WebApplication1.Controllers { public class TestController : Controller { private readonly IHttpClientFactory _clientFactory;public TestController(IHttpClientFactory clientFactory) { _clientFactory = clientFactory; } /// <summary> /// 基本用法 /// </summary> /// <returns></returns> [HttpGet] public async Task<string> Get() { HttpClient client = _clientFactory.CreateClient(); //方法一: HttpRequestMessage request = new HttpRequestMessage { Method = new HttpMethod("get"), RequestUri = new System.Uri("http://127.0.0.1:8067/api/values"), }; HttpResponseMessage response = await client.SendAsync(request); string res = await response.Content.ReadAsStringAsync(); return res; ////方法二: //string res = await client.GetStringAsync("http://127.0.0.1:8067/api/values/1"); //return res; }public IActionResult Index() { var aa= Get(); var bb = aa.Result;return View(); } } }
二、命名客户端
在 Startup中的ConfigureServices中
//命名客户端 services.AddHttpClient("test", c => { c.BaseAddress = new Uri("http://127.0.0.1:8067"); });
/// <summary> /// 命名客户端 /// </summary> /// <returns></returns> public async Task<string> Get() { HttpClient client = _clientFactory.CreateClient("test"); //注册名叫 "test" 的客户端时,已经指定了该客户端的请求基地址,所以这里不需要指定主机名了 return await client.GetStringAsync("api/values"); }
三、类型化客户端
在 Startup中的ConfigureServices中 ,这里就是注入时配置HttpClient
//类型化客户端 services.AddHttpClient<TestHttpClient>(c => { //可以在这里设置,也可以在构造函数设置. //c.BaseAddress = new System.Uri("http://127.0.0.1:8067"); });
新建个类 TestHttpClient
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading.Tasks; namespace WebApplication1.Content { public class TestHttpClient { public HttpClient Client { get; set; } public TestHttpClient(HttpClient client) { client.BaseAddress = new System.Uri("http://127.0.0.1:8067"); Client = client; } public async Task<string> Get(string url) { return await Client.GetStringAsync(url); } public async Task<HttpResponseMessage> Post<T>(string url,T t) { return await Client.PostAsJsonAsync(url,t); } } }
/// <summary> /// 类型化客户端 /// </summary> /// <returns></returns> [HttpGet] public async Task<string> Get() { return await _client.Get("api/values"); } public async Task<HttpResponseMessage> Post() { //若返回400 则原因可能是本地客户端参数与api参数不一致 Text t = new Text() { value = "123" }; return await _client.Post("api/values", t); } public IActionResult Index() { var aa= Get(); var bb = aa.Result; var cc = Post(); var dd = cc.Result; if (dd.IsSuccessStatusCode) { var res = dd.Content.ReadAsStringAsync(); var ee= res.Result; } return View(); } public class Text { public string value { get; set; } }
api这边就是默认的,改了个post 参数类型要一致
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; namespace Api.Controllers { [Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { // GET api/values [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { "value1", "value2" }; } // GET api/values/5 [HttpGet("{id}")] public ActionResult<string> Get(int id) { return "value"; } // POST api/values [HttpPost] public string Post([FromBody]Text value) { return "post method"; } // PUT api/values/5 [HttpPut("{id}")] public void Put(int id, [FromBody] string value) { } // DELETE api/values/5 [HttpDelete("{id}")] public void Delete(int id) { } } public class Text { public string value { get; set; } } }
可以将 HttpClient
完全封装在类型化客户端中。 不是将它公开为属性,而是可以提供公共方法,用于在内部调用 HttpClient
。
参考资料:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2