在.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