Norns.Urd.HttpClient
Norns.Urd.HttpClient 基於AOP框架 Norns.Urd實現,
是對 System.Net.Http
下的 HttpClient封裝,讓大家只需簡單在介面定義就可以實現http的呼叫,可以減少一些重複程式碼的書寫。
可以和已有的 Norns.Urd.Extensions.Polly
以及 Norns.Urd.Caching.Memory
配合使用。
原始碼放在:https://github.com/fs7744/Norns.Urd
如何啟用 HttpClient 功能
- 引入Norns.Urd.HttpClient
dotnet add package Norns.Urd.HttpClient
- 程式碼中開啟 HttpClient 功能,只需
new ServiceCollection()
.ConfigureAop(i => i.EnableHttpClient())
- 定義 要使用的 HttpClient 介面
舉例如:
[BaseAddress("http://localhost.:5000")]
public interface ITestClient
{
[Get("WeatherForecast/file")]
[AcceptOctetStream]
Task<Stream> DownloadAsync();
[Post("WeatherForecast/file")]
[OctetStreamContentType]
Task UpoladAsync([Body]Stream f);
}
- 註冊到 ioc 中
new ServiceCollection()
.AddSingleton<ITestClient>() // 按照自己需要設定生命週期就好,並且不需要寫具體實現,Norns.Urd.HttpClient會為您生成對應IL程式碼
.ConfigureAop(i => i.EnableHttpClient())
- 通過DI 使用就好, 比如
[ApiController]
[Route("[controller]")]
public class ClientController : ControllerBase
{
private readonly ITestClient client;
public ClientController(ITestClient client)
{
this.client = client;
}
[HttpGet("download")]
public async Task<object> DownloadAsync()
{
using var r = new StreamReader(await client.DownloadAsync());
return await r.ReadToEndAsync();
}
}
HttpClient支援的功能
Url 配置
BaseAddress
如果有些網站域名或者基礎api地址都是很多介面都會使用的,就可以在介面上使用 BaseAddressAttribute
如:
[BaseAddress("http://localhost.:5000")]
public interface ITestClient
各種 Http Method 支援設定Url
Http Method 支援如下:
- GetAttribute
- PostAttribute
- PutAttribute
- DeleteAttribute
- PatchAttribute
- OptionsAttribute
- HeadAttribute
(上述method 不夠使用時,可以繼承HttpMethodAttribute
自定義實現)
所有的這些Http Method都支援配置Url,有以下兩種方式支援:
- 靜態配置
[Post("http://localhost.:5000/money/getData/")]
public Data GetData()
- 動態配置
預設支援從 IConfiguration
通過key獲取 url 配置
[Post("configKey", IsDynamicPath = true)]
public Data GetData()
如果這樣簡單的配置形式不支援您的需求,可以實現 IHttpRequestDynamicPathFactory
介面替換配置實現方式,實現好的類只需註冊到IOC容器就可以了。
實現示例可以參考 ConfigurationDynamicPathFactory
路由引數設定
如果某些url 路由引數需要動態設定,您可以通過RouteAttribute
設定, 如
[Post("getData/{id}")]
public Data GetData([Route]string id)
如果引數名字不匹配url裡面的設定,可以通過Alias =
設定,如
[Post("getData/{id}")]
public Data GetData([Route(Alias = "id")]string number)
Query string 設定
Query string引數可以在方法引數列表中設定
[Post("getData")]
public Data GetData([Query]string id);
//or
[Post("getData")]
public Data GetData([Query(Alias = "id")]string number);
其Url結果都為 getData?id=xxx
,
引數型別支援基本型別和 class,
當為class 時,會取class的屬性作為引數,
所以當屬性名不匹配定義時,可以在屬性上用 [Query(Alias = "xxx")]
指定
Request body 設定
Request body 可以通過可以在方法引數列表中設定BodyAttribute
指定引數,
需注意,只有第一個有BodyAttribute
的引數會生效, 舉例如
public void SetData([Body]Data data);
將根據設定的 Request Content-Type 選擇序列化器序列化body
Response body 設定
Response body 的型別指定,只需在方法的 return type 寫上需要的型別就好,支援以下
- void (忽略反序列化)
- Task (忽略反序列化)
- ValueTask (忽略反序列化)
- T
- Task
- ValueTask
- HttpResponseMessage
- Stream (只能Content-Type為 application/octet-stream 時起效)
舉例如:
public Data GetData();
Content-Type 設定
無論 Request 還是 Response 的 Content-Type 都會影響 序列化和反序列化器的選擇,
預設支援json/xml的序列化和反序列化,可以通過如下設定
- JsonContentTypeAttribute
- XmlContentTypeAttribute
- OctetStreamContentTypeAttribute
舉例如:
[OctetStreamContentType]
public Data GetData([Body]Stream s);
對應的Accept 設定為
- AcceptJsonAttribute
- AcceptXmlAttribute
- AcceptOctetStreamAttribute
舉例如:
[AcceptOctetStream]
public Stream GetData();
json 序列化器預設為 System.Text.Json
更換json 序列化器為 NewtonsoftJson
- 引入
Norns.Urd.HttpClient.NewtonsoftJson
- 在 ioc 註冊方法, 如
new ServiceCollection().AddHttpClientNewtonsoftJosn()
自定義序列化器
當現有序列化器不足以支援需求時,
只需實現 IHttpContentSerializer
並向 ioc 容器註冊即可
自定義 Header
除了上述已經提到的header之外,還可以通過新增其他header
同樣有以下兩種方式:
- 使用
HeaderAttribute
在介面或方法靜態配置
[Header("x-data", "money")]
public interface ITestClient {}
//or
[Header("x-data", "money")]
public Data GetData();
- 方法引數動態配置
public Data GetData([SetRequestHeader("x-data")]string header);
自定義HttpRequestMessageSettingsAttribute
當現有HttpRequestMessageSettingsAttribute
不足以支援需求時,
只需繼承 HttpRequestMessageSettingsAttribute
實現自己的功能,
在對應的介面/方法使用即可
通過引數設定獲取 Response Header
當有時我們需要獲取 response 返回的 header 時,
我們可以 out 引數 + OutResponseHeaderAttribute
獲取 Response Header的值
(需注意, 只有同步方法, out引數才能起作用)
舉例如:
public Data GetData([OutResponseHeader("x-data")] out string header);
HttpClient 一些引數設定方法
MaxResponseContentBufferSize
[MaxResponseContentBufferSize(20480)]
public interface ITestClient {}
//or
[MaxResponseContentBufferSize(20480)]
public Data GetData()
Timeout
[Timeout("00:03:00")]
public interface ITestClient {}
//or
[Timeout("00:03:00")]
public Data GetData()
ClientName
當需要結合 HttpClientFactory 獲取特殊設定的 HttpClient 時,可以通過ClientNameAttribute
指定
如
[ClientName("MyClient")]
public interface ITestClient {}
//or
[ClientName("MyClient")]
public Data GetData()
就可以獲取到這樣指定的HttpClient
services.AddHttpClient("MyClient", i => i.MaxResponseContentBufferSize = 204800);
HttpCompletionOption
HttpClient 呼叫時的 CompletionOption 引數同樣可以設定
HttpCompletionOption.ResponseHeadersRead 是預設配置
如
[HttpCompletionOption(HttpCompletionOption.ResponseContentRead)]
public interface ITestClient {}
//or
[HttpCompletionOption(HttpCompletionOption.ResponseContentRead)]
public Data GetData()
全域性 HttpRequestMessage 和 HttpResponseMessage 處理
如果需要全域性對 HttpRequestMessage 和 HttpResponseMessage 做一些處理,比如:
- 鏈路追蹤id 設定
- response 異常自定義處理
可以通過實現IHttpClientHandler
並向ioc 容器註冊使用
舉例預設的 status code 檢查 ,如:
public class EnsureSuccessStatusCodeHandler : IHttpClientHandler
{
public int Order => 0;
public Task SetRequestAsync(HttpRequestMessage message, AspectContext context, CancellationToken token)
{
return Task.CompletedTask;
}
public Task SetResponseAsync(HttpResponseMessage resp, AspectContext context, CancellationToken token)
{
resp.EnsureSuccessStatusCode();
return Task.CompletedTask;
}
}
當然,如果該 StatusCode 檢查處理不需要的話,可以直接在ioc 容器清除掉, 如:
services.RemoveAll<IHttpClientHandler>();
// 然後新增自己的處理
services.AddSingleton<IHttpClientHandler, xxx>();
有任何問題歡迎大家提issue (_)