介绍一个新库: Norns.Urd.HttpClient
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 (_)
介绍一个新库: Norns.Urd.HttpClient的更多相关文章
- 介绍一个golang库:fastcache
学习VictoriaMetrics源码的时候发现,VictoriaMetrics的缓存部分,使用了同一产品下的fastcache.下面分享阅读fastcache源码的的结论: 1.官方介绍 fastc ...
- MSSQL-Scripter,一个新的生成T-SQL脚本的SQL Server命令行工具
这里向大家介绍一个新的生成T-SQL脚本的SQL Server命令行工具:mssql-scripter.它支持在SQL Server.Azure SQL DB以及Azure SQL DW中为数据库生成 ...
- 介绍一个python视频处理库:moviepy
由于博客园的插件和我自己博客的插件不一致,代码以及视频插入转换很麻烦,所以还是我原来博客的地址查看吧. 介绍一个python视频处理库:moviepy
- 使用source创建一个新项目(将本地项目文件和github远程库链接)
1. 本地创建项目文件夹 2. 将本地的项目添加到source中(我使用的source版本为2.4.7.0) 3. github创建远程库 4. 关联本地项目文件和github库 确定添加就可以了. ...
- Git库搭建好之后,当要提交一个新的文件,需要做的是3个步骤
Git库搭建好之后,当要提交一个新的文件,需要做的是3个步骤 1.git add new.txt 2.git commit -m "add a new file" 3.git pu ...
- 【Hades】ades是一个开源库,基于JPA和Spring构建,通过减少开发工作量显著的改进了数据访问层的实现
几乎每个应用系统都需要通过访问数据来完成工作.要想使用领域设计方法,你就需要为实体类定义和构建资源库来实现领域对象的持久化.目前开发人员经常使用JPA来实现持久化库.JPA让持久化变得非常容易,但是仍 ...
- GitHub 常用命令使用介绍(新同学入门)
经济在不断发展,社会在不断进步,以往的互联网在现在看来都可以称为传统互联网了,因为技术不断的在突破和革新. 本文主要介绍一下版本管理工具,我猜测很多人还是用SVN.CVS或者Resion,但是,今天我 ...
- 教你一步步发布一个开源库到 JCenter
今天想来分享下,如何一步步自己发布一个开源库到 JCenter 这方面的博客网上已经特别多了,所以本篇并不打算仅仅只是记录流程步骤而已,而是尽可能讲清楚,为什么需要有这个步骤,让大伙知其然的同时还知其 ...
- 你不需要 jQuery,但你需要一个 DOM 库
写这篇文章的目的,一方面是介绍一下自己编写的模块化 DOM 库 domq.js,另一方面是希望大家对 jQuery 有一个正确的认识,即使 jQuery 已经逐渐退出历史舞台,但是它的 API 将会以 ...
随机推荐
- [Java复习]架构部署 超时重试 幂等防重
画一下你们系统的整体架构图,说说各个服务在生产环境怎么部署的? 核心:服务框架.注册中心.网关 即使你没有用很多微服务架构里的东西,只要有上述三个东西,配合上写一些文档,接口文档,分布式系统架构,其实 ...
- IDM 汉化版v1.1.10 (NDM汉化版)
提升你的下载速度最多达 5 倍,安排下载时程,或续传一半的软件.Internet Download Manager 的续传功能可以恢复因为断线.网络问题.计算机当机甚至无预警的停电导致下传到一半的软件 ...
- spring入门学习
开发步骤: 1.导入Spring开发的基本坐标 2.编写接口和实现类 3.创建Spring核心配置文件 4.在Spring核心配置文件中配置实现类 5.使用Spring的API获得Bean实例Bean ...
- 【操作系统】页面置换算法(最佳置换算法)(C语言实现)
[操作系统]页面置换算法(最佳置换算法)(C语言实现) (编码水平较菜,写博客也只是为了个人知识的总结和督促自己学习,如果有错误,希望可以指出) 1.页面置换算法: 在地址映射过程中,若在页面中发现所 ...
- 实验:非GTID 一主多从变级联架构
- git远程仓库Github
一.克隆项目 git clone 网址 1.配置信息 git config user.name '用户名' git config user.email '邮箱号' 2.推送项目到远程仓库 # 工作区代 ...
- js下 Day11、案例
一.成绩分类 效果图: 功能思路分析: 1. 渲染数据 2. 鼠标按下开启拖拽 \1. 给成绩盒子绑定鼠标按下事件(mousedown),用事件委托做多个标签的拖拽 \2. 开启控制拖拽的变量 \3. ...
- MySQL中的 ”SELECT FOR UPDATE“ 一次实践
背景 最近工作中遇到一个问题,两个不同的线程会对数据库里的一条数据做修改,如果不加锁的话,会得到错误的结果. 就用了MySQL中for update 这种方式来实现 本文主要测试主键.唯一索引和普通索 ...
- java_day 02
一.方法的传入参数可以为一个 类 类型 有往方法里传 int ,double ,char 类型的值的,第一次学习到居然还能往方法里传 类 定义好一个 Phone 类 实例化对象 ,并且往 method ...
- 面试官问我:Object o = new Object() 占用了多少个字节?
小小面试一下 前言蜜语 最近马师傅火的不要不要的,虽然没有抢到耗子尾汁的商标注册权,但是必须得蹭一波马师傅的热度,下面就是闪电五连鞭的教学环节,你准备好了吗! 在正式内容开始前先甩两篇关于类加载机制和 ...