深入淺出Blazor webassembly之HttpClient使用
===================================
參考
===================================
http://www.rzrgm.cn/deepthought/p/11303015.html
http://www.rzrgm.cn/willick/p/net-core-httpclient.html
技術(shù)譯民翻譯的博客 http://www.rzrgm.cn/ittranslator/p/making-http-requests-in-blazor-webassembly-apps.html
===================================
直接使用 HttpClient 的問(wèn)題
===================================
HttpClient 類所在庫(kù)為 System.Net.Http,
Blazor webassembly 默認(rèn)模版已經(jīng)自動(dòng)將HttpClient 注冊(cè)到DI 容器中了, 使用起來(lái)非常方便. Program.Main 函數(shù)注冊(cè)DI容器代碼:
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
直接使用 HttpClient 問(wèn)題有:
- HttpClient 主要問(wèn)題是, 即使 Dispose 之后, 也不能即時(shí)關(guān)閉 socket 連接, 在 windows 下, 默認(rèn)需要等 240秒之后才能關(guān)閉 socket. 短時(shí)大量使用 HttpClient, 會(huì)將客戶端和服務(wù)器端 socket 連接消耗殆盡, 詳見(jiàn)參考文檔1的分析. 所以, 客戶端應(yīng)用程序一般使用單例模式使用 HttpClient 類. Blazor webassembly 也是如此.
- 如果使用單例模式, 如要為 不同url 設(shè)置不同的 header, 就很不方便.
- HttpClient 還會(huì)緩存 IP, 如果 DNS 之后有更新, HttpClient 仍會(huì)使用老的 IP
Net Core2.1 提供的 IHttpClientFactory 解決了直接使用HttpClient的所有問(wèn)題, IHttpClientFactory 提供了更優(yōu)雅 Http Client 功能.
===================================
IHttpClientFactory 簡(jiǎn)單方法生成 HttpClient
===================================
IHttpClientFactory 所在的類庫(kù)是 Microsoft.Extensions.Http , 將它加到blazor wasm 項(xiàng)目的依賴中,
Program.Main 函數(shù)必須使用 AddHttpClient 完成DI容器注冊(cè), 這樣DI容器就能為我們注入 IHttpClientFactory 實(shí)例.
builder.Services.AddHttpClient();
Razor 頁(yè)面使用 IHttpClientFactory 的實(shí)例生成 HttpClient 對(duì)象.
@page "/hello" @inject IHttpClientFactory HttpClientFactory <div> _statusCode: @_statusCode </div> @code{ private string _statusCode = ""; protected override async Task OnInitializedAsync() { var httpClient = HttpClientFactory.CreateClient(); //gorest.co.in 網(wǎng)站已經(jīng)開(kāi)啟 CORS 共享, 所以我們用它來(lái)測(cè)試, 而不是 https://www.baidu.com httpClient.BaseAddress=new Uri("https://gorest.co.in"); var result = await httpClient.GetAsync("/public/v1/users"); _statusCode = result.StatusCode.ToString(); } }
使用這個(gè)簡(jiǎn)單的方式, IHttpClientFactory 注入的實(shí)例未經(jīng)任何初始化, 比如未設(shè)置BaseAddress參數(shù), 需要在使用該實(shí)例時(shí)候, 進(jìn)行各種設(shè)置, 代碼復(fù)用性較差.
===================================
IHttpClientFactory 采用命名方式生成 HttpClient
===================================
命名方式在使用友好性方面比簡(jiǎn)單方式好很多.
注冊(cè)DI容器時(shí), AddHttpClient()傳入名稱, 同時(shí)還可以為將來(lái)的HttpClient對(duì)象設(shè)置各種參數(shù).
使用時(shí), 先獲取注入的 IHttpClientFactory HttpClient實(shí)例, 然后CreateClient()傳入命名值即可得到經(jīng)過(guò)預(yù)設(shè)的HttpClient對(duì)象對(duì)象 , 不需要再進(jìn)行參數(shù)設(shè)置.
builder.Services.AddHttpClient(name: "gorest", c => { c.BaseAddress = new Uri("https://gorest.co.in"); } );
@page "/hello" @inject IHttpClientFactory HttpClientFactory <div> _statusCode: @_statusCode </div> @code{ private string _statusCode = ""; protected override async Task OnInitializedAsync() { var httpClient = HttpClientFactory.CreateClient(name: "gorest"); var result = await httpClient.GetAsync("/public/v1/users"); _statusCode = result.StatusCode.ToString(); } }
===================================
IHttpClientFactory 采用類型化方式生成 HttpClient
===================================
類型化方式比命名方式更進(jìn)一步, 注冊(cè)DI容器時(shí), AddHttpClient()傳入一個(gè)泛型類型, 將HttpClient的各種設(shè)置轉(zhuǎn)移到泛型類中
這樣的好處時(shí), AddHttpClient() 方法更簡(jiǎn)單, 代碼內(nèi)聚性更好.
包裝了 HttpClient 的泛型類:
public class GorestHttpService { private readonly HttpClient _httpClient; public GorestHttpService(HttpClient httpClient) { _httpClient = httpClient; _httpClient.BaseAddress = new Uri("https://gorest.co.in"); } public async Task<string> GetStatusCodeAsync() { var result = await _httpClient.GetAsync("/public/v1/users"); return result.StatusCode.ToString(); } }
Program.Main 函數(shù) AddHttpClient 完成DI容器注冊(cè)
builder.Services.AddHttpClient<GorestHttpService>();
Razor 代碼:
@page "/hello" @inject GorestHttpService gorestHttpService <div> _statusCode: @_statusCode </div> @code{ private string _statusCode = ""; protected override async Task OnInitializedAsync() { var result = await gorestHttpService.GetStatusCodeAsync(); _statusCode = result; } }
===================================
為 HttpClient 增加 Header
===================================
如需要增加 Bearer Header, 可以通過(guò)為 httpClient.DefaultRequestHeaders.Authorization 屬性賦值.
public class GorestHttpService { private readonly HttpClient _httpClient; public GorestHttpService(HttpClient httpClient) { _httpClient = httpClient; _httpClient.BaseAddress = new Uri("https://gorest.co.in"); string token = "changeMe"; _httpClient.DefaultRequestHeaders.Authorization= new AuthenticationHeaderValue("Bearer", token); } public async Task<string> GetStatusCodeAsync() { var result = await _httpClient.GetAsync("/public/v1/users"); return result.StatusCode.ToString(); } }
Jwt token 使用 Bearer head, Basic 驗(yàn)證使用:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "base64 user:pwd")
或者加Header 文本:
HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer <token>"); HttpClient.DefaultRequestHeaders.Add("Authorization", "Basic "+"base64 user:pwd")
===================================
開(kāi)放的 Rest api 服務(wù)
===================================
示例中使用了 GoRest 網(wǎng)站, 它是 Online REST API for Testing and Prototyping https://gorest.co.in/
一些簡(jiǎn)單的api網(wǎng)站 https://mixedanalytics.com/blog/list-actually-free-open-no-auth-needed-apis/

浙公網(wǎng)安備 33010602011771號(hào)