19. 远程请求
📝 模块更新日志
-
新特性
- 远程请求
[HttpMethod]ToSaveAsync
下载远程文件并保存到磁盘方法 4.8.7.32 ⏱️2023.04.02 bfd02c1 - 远程请求支持
Content-Type
为text/html
和text/plain
处理 4.8.7.22 ⏱️2023.03.27 #I6QMLR - 远程请求
HttpRequestMessage
拓展方法AppendHeaders
4.8.7.10 ⏱️2023.03.14 #I6MVHT - 远程请求配置
SetHttpVersion(version)
配置,可配置HTTP
请求版本,默认为1.1
4.8.5.8 ⏱️2023.02.06 #I6D64H - 远程请求
[QueryString]
特性添加时间格式化Format
属性 4.8.1.2 ⏱️2022.11.24 !670
- 远程请求
-
问题修复
- 远程请求获取响应
Cookies
被截断问题 4.8.8.54 ⏱️2023.11.08 #I8EV1Z - 远程请求上传文件在其他编程语言获取文件名存在双引号问题 4.8.8.53 ⏱️2023.11.07 #I8EF1S
- 远程请求在被请求端返回非
200
状态码但实际请求已处理也抛异常问题 4.8.8.14 ⏱️2023.05.12 b14a51f - 远程请求
Body
参数为粘土对象Clay
类型序列化有误 4.8.8.1 ⏱️2023.04.18 #I6WKRZ - 远程请求获取
Cookies
时如果包含相同Key
异常问题 4.8.7.44 ⏱️2023.04.12 #I6V3T7 - 远程请求代理模式配置了
WithEncodeUrl = false
无效问题 4.8.6.4 ⏱️2023.02.16 89639ba - 由于 #I6D64H 导致远程请求出现
Specified method is not supported.
问题 4.8.5.9 ⏱️2023.02.07 #I6DEEE #I6D64H -
优化远程请求ReadAsStringAsync
底层方法,尝试修复Error while copying content to a stream.
错误 4.8.5.8 ⏱️2023.02.06 #I6D64H - 远程请求配置
WithEncodeUrl(false)
对application/x-www-form-urlencoded
请求类型无效 4.8.4 ⏱️2022.12.30 #I682DX
- 远程请求获取响应
-
其他更改
- 取消远程请求
GET/HEAD
不能传递Body
的限制 4.8.8.39 ⏱️2023.08.02 8113460
- 取消远程请求
-
文档
- 远程请求
[QueryString]
配置时间类型Format
格式化文档 4.8.1.2 ⏱️2022.11.25 !673
- 远程请求
以下内容仅限 Furion 1.16.0 +
版本使用。
19.1 关于远程请求
在互联网大数据的驱动下,平台或系统免不了需要和第三方进行数据交互,而第三方往往提供了 RESTful API
接口规范,这个时候就需要通过 Http
请求第三方接口进行数据传输交互。
也就是本章节所说的远程请求。
19.2 远程请求的作用
- 跨系统、跨设备通信
- 实现多个系统数据传输交互
- 跨编程语言协同开发
19.3 基础使用
19.3.1 注册服务
使用之前需在 Startup.cs
注册 远程请求服务
public void ConfigureServices(IServiceCollection services)
{
services.AddRemoteRequest();
}
19.3.2 使用方式
Furion
提供两种方式访问发送远程请求。
- IHttpDispatchProxy 代理方式
- 字符串拓展方式
定义代理请求的 接口
并继承 IHttpDispatchProxy
接口
public interface IHttp : IHttpDispatchProxy
{
[Get("http://furion.baiqian.ltd/get")]
Task<Result> GetXXXAsync();
[Post("http://furion.baiqian.ltd/post")]
Task<Result> PostXXXAsync();
[Put("http://furion.baiqian.ltd/put")]
Task<Result> PutXXXAsync();
[Delete("http://furion.baiqian.ltd/delete")]
Task<Result> DeleteXXXAsync();
[Patch("http://furion.baiqian.ltd/patch")]
Task<Result> PatchXXXAsync();
[Head("http://furion.baiqian.ltd/head")]
Task<Result> HeadXXXAsync();
}
通过构造函数注入 接口
using Furion.DynamicApiController;
using Furion.RemoteRequest.Extensions;
namespace Furion.Application
{
public class RemoteRequestService : IDynamicApiController
{
private readonly IHttp _http;
public RemoteRequestService(IHttp http)
{
_http = http;
}
public async Task GetData()
{
var data = await _http.GetXXXAsync();
}
}
}
var response = await "http://furion.baiqian.ltd/get".GetAsync();
var response = await "http://furion.baiqian.ltd/post".PostAsync();
var response = await "http://furion.baiqian.ltd/put".PutAsync();
var response = await "http://furion.baiqian.ltd/delete".DeleteAsync();
var response = await "http://furion.baiqian.ltd/patch".PatchAsync();
var response = await "http://furion.baiqian.ltd/head".HeadAsync();
需引入 using Furion.RemoteRequest.Extensions
命名空间。
19.4 字符串方式使用示例
推荐使用 《19.5 代理方式》代替本小节功能。代理方式
能够提供更容易且更易维护的方式。
19.4.1 内置请求方式
// 发送 Get 请求
var response = await "http://furion.baiqian.ltd/get".GetAsync();
// 发送 Post 请求
var response = await "http://furion.baiqian.ltd/post".PostAsync();
// 发送 Put 请求
var response = await "http://furion.baiqian.ltd/put".PutAsync();
// 发送 Delete 请求
var response = await "http://furion.baiqian.ltd/delete".DeleteAsync();
// 发送 Patch 请求
var response = await "http://furion.baiqian.ltd/patch".PatchAsync();
// 发送 Head 请求
var response = await "http://furion.baiqian.ltd/head".HeadAsync();
// 手动指定发送特定请求
var response = await "http://furion.baiqian.ltd/post".SetHttpMethod(HttpMethod.Post)
.SendAsync();
19.4.2 设置请求地址
// 该方式在 Furion v3.0.0 已移除,多此一举了
await "".SetRequestUrl("http://furion.baiqian.ltd/");
19.4.3 设置请求方式
await "http://furion.baiqian.ltd/post".SetHttpMethod(HttpMethod.Get);
19.4.4 设置地址模板
// 字典方式
await "http://furion.baiqian.ltd/post/{id}?name={name}&id={p.Id}".SetTemplates(new Dictionary<string , object> {
{ "id", 1 },
{ "name", "Furion" },
{ "p.Id", new Person { Id = 1 } }
});
// 对象/匿名对象方式
await "http://furion.baiqian.ltd/post/{id}?name={name}".SetTemplates(new {
id = 1,
name = "Furion"
});
注:模板替换区分大小写。
19.4.5 设置请求报文头
// 字典方式
await "http://furion.baiqian.ltd/post".SetHeaders(new Dictionary<string , object> {
{ "Authorization", "Bearer 你的token"},
{ "X-Authorization", "Bearer 你的刷新token"}
});
// 对象/匿名对象方式
await "http://furion.baiqian.ltd/post".SetHeaders(new {
Authorization = "Bearer 你的token"
});
19.4.6 设置 URL
地址参数
// 字典方式
await "http://furion.baiqian.ltd/get".SetQueries(new Dictionary<string , object> {
{ "id", 1 },
{ "name", "Furion"}
});
// 对象/匿名对象方式
await "http://furion.baiqian.ltd/get".SetQueries(new {
id = 1,
name = "Furion"
});
// Furion 4.7.3+ 新增忽略 null 值重载
await "http://furion.baiqian.ltd/get".SetQueries(new {
id = 1,
name = "Furion",
nullValue = default(object)
}, true); // 设置 true 则忽略 null 值
最终输出格式为:http://furion.baiqian.ltd/get?id=1&name=Furion
。
19.4.7 设置请求客户端
- 全局配置方式
services.AddRemoteRequest(options=>
{
// 配置 Github 基本信息
options.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
});
await "get".SetClient("github");
最终生成请求地址为:https://api.github.com/get
。
- 局部配置方式
以下内容仅限 Furion 4.3.8 +
版本使用。
await "http://furion.baiqian.ltd".SetClient(() => new HttpClient());
19.4.8 设置 Body
参数
// 传入对象
await "http://furion.baiqian.ltd/api/user/add".SetBody(new User { Id = 1, Name = "Furion" });
// 配置 Content-Type
await "http://furion.baiqian.ltd/api/user/add".SetBody(new { Id = 1, Name = "Furion" }, "application/json");
// 设置 Encoding 编码
await "http://furion.baiqian.ltd/api/user/add".SetBody(new User { Id = 1, Name = "Furion" }, "application/json", Encoding.UTF8);
// 处理 application/x-www-form-urlencoded 请求
await "http://furion.baiqian.ltd/api/user/add".SetBody(new Dictionary<string , object> {
{ "Id", 1 },
{ "Name", "Furion"}
}, "application/x-www-form-urlencoded");
// 处理 application/xml、text/xml
await "http://furion.baiqian.ltd/api/user/add".SetBody("<SomeDto><SomeTag>somevalue</SomeTag></SomeDto>", "application/xml");
如果请求 Content-Type
设置为 application/x-www-form-urlencoded
类型,那么底层自动将数据进行 UrlEncode
编码处理,无需外部处理。
19.4.9 设置 Content-Type
await "http://furion.baiqian.ltd/post".SetContentType("application/json");
19.4.10 设置内容编码
await "http://furion.baiqian.ltd/post".SetContentEncoding(Encoding.UTF8);
19.4.11 设置 JSON
序列化提供程序
Furion
默认情况下采用 System.Text.Json
进行 JSON
序列化处理,如需设置第三方 JSON
提供器,则可以通过以下配置:
// 泛型方式
await "http://furion.baiqian.ltd/api/user/add".SetJsonSerialization<NewtonsoftJsonSerializerProvider>();
// 非泛型方式
await "http://furion.baiqian.ltd/api/user/add".SetJsonSerialization(typeof(NewtonsoftJsonSerializerProvider));
// 添加更多配置
await "http://furion.baiqian.ltd/api/user/add".SetJsonSerialization<NewtonsoftJsonSerializerProvider>(new JsonSerializerSettings {
});
// 比如配置缺省的序列化选项
await "http://furion.baiqian.ltd".SetJsonSerialization(default, new JsonSerializerOptions
{
// 中文乱码
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
})
.GetAsAsync();
JSON
序列化提供器如需了解 更多 JSON
序列化知识可查阅 23. JSON 序列化 章节
19.4.12 启用 Body
参数验证
await "http://furion.baiqian.ltd/api/user/add".SetValidationState();
// 设置不验证 null 值
await "http://furion.baiqian.ltd/api/user/add".SetValidationState(includeNull: true);
支持类中 [Required]
等完整模型验证特性。
19.4.13 请求拦截
await "http://furion.baiqian.ltd/".OnRequesting((client, req) => {
// req 为 HttpRequestMessage 对象
// 追加更多参数
req.AppendQueries(new Dictionary<string, object> {
{ "access_token", "xxxx"}
});
});
支持多次拦截
19.4.14 HttpClient
拦截
await "http://furion.baiqian.ltd/".OnClientCreating(client => {
// client 为 HttpClient 对象
client.Timeout = TimeSpan.FromSeconds(30); // 设置超时时间
});
支持多次拦截
19.4.15 请求之前拦截
await "http://furion.baiqian.ltd/".OnRequesting((client, req) => {
// req 为 HttpRequestMessage 对象
});
支持多次拦截
19.4.16 成功请求拦截
await "http://furion.baiqian.ltd/".OnResponsing((client, res) => {
// res 为 HttpResponseMessage 对象
});
支持多次拦截
19.4.17 请求异常拦截
await "http://furion.baiqian.ltd/".OnException((client, res, errors) => {
// res 为 HttpResponseMessage 对象
});
支持多次拦截
19.4.18 各种返回值处理
Furion
远程请求默认提供四种返回值类型:
HttpResponseMessage
:请求响应消息类型Stream
:流类型,可用来下载文件T
:泛型T
类型String
:字符串类型,也就是直接将网络请求结果内容字符串化Byte[]
:字节数组类型
如:
// HttpResponseMessage
var res = await "http://furion.baiqian.ltd/".GetAsync();
// Stream,可用来下载文件
var (stream, encoding) = await "http://furion.baiqian.ltd/".GetAsStreamAsync();
// T
var user = await "http://furion.baiqian.ltd/".GetAsAsync<User>();
// String
var str = await "https://www.baidu.com".GetAsStringAsync();
19.4.19 设置 Byte[]/Stream
类型/上传文件
Furion 4.4.0
以下版本在 Furion 4.4.0+
版本移除了 .SetBodyBytes
方式,原因是拓展性太差,新版本请使用 .SetFiles
方式。
有时候我们需要上传文件,需要设置 Content-Type
为 multipart/form-data
类型,如:
// 支持单文件,bytes 可以通过 File.ReadAllBytes(文件路径) 获取
var res = await "http://furion.baiqian.ltd/upload".SetContentType("multipart/form-data")
.SetBodyBytes(("键", bytes, "文件名")).PostAsync();
// 支持多个文件
var res = await "http://furion.baiqian.ltd/upload".SetContentType("multipart/form-data")
.SetBodyBytes(("键", bytes, "文件名"),("键", bytes, "文件名")).PostAsync();
// 支持单文件,Furion 4.5.8 版本支持 Stream 方式更新
var res = await "http://furion.baiqian.ltd/upload".SetContentType("multipart/form-data")
.SetBodyBytes(("键", fileStream, "文件名")).PostAsync();
// 支持多个文件,Furion 4.5.8 版本支持 Stream 方式更新
var res = await "http://furion.baiqian.ltd/upload".SetContentType("multipart/form-data")
.SetBodyBytes(("键", fileStream, "文件名"),("键", fileStream, "文件名")).PostAsync();
如果遇到微信上传出现问题,则可设置 Content-Type
为:application/octet-stream
,如:
var result = await $"https://api.weixin.qq.com/wxa/img_sec_check?access_token={token}"
.SetBodyBytes(("media", bytes, Path.GetFileName(imgPath)))
.SetContentType("application/octet-stream")
.PostAsStringAsync();
Furion 4.4.0+
版本如果使用 Furion 4.4.0+
版本,请使用以下的 .SetFiles
替代 .SetBodyBytes
操作。
// bytes 可以通过 File.ReadAllBytes(文件路径) 获取
var res = await "http://furion.baiqian.ltd/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.Create("file", bytes, "image.png")).PostAsync();
// 支持多个文件
var res = await "http://furion.baiqian.ltd/upload".SetContentType("multipart/form-data")
.SetFiles(HttpFile.CreateMultiple("files", (bytes, "image1.png"), (bytes, "image2.png"))).PostAsync();
19.4.20 设置 IServiceProvider
有时候我们需要构建一个作用域的 IServiceProvider
,这时只需要设置即可:
var res = await "http://furion.baiqian.ltd/upload".SetRequestScoped(services);
19.4.21 支持模板配置
模板格式为:#(配置路径)
var res = await "#(Furion:Address)/upload".GetAsync();
{
"Furion": {
"Address": "http://furion.baiqian.ltd"
}
}
19.4.22 重试策略
在 Furion v2.18+
版本支持配置重试策略,如:
var res = await "http://furion.baiqian.ltd".SetRetryPolicy(3, 1000).GetAsync();
以上代码表示请求失败重试 3
次,每次延迟 1000ms
。
19.4.23 支持 GZip
压缩
在 Furion v3.2.0+
版本支持GZip
压缩,如:
var res = await "http://furion.baiqian.ltd".WithGZip().GetAsync();
19.4.24 设置 Url
转码
过去版本会对所有的 Url
进行 Uri.EscapeDataString
转码,在 Furion v3.8.0+
版本支持 Url
转码设置,如:
var res = await "http://furion.baiqian.ltd".WithEncodeUrl(false).GetAsync();
19.4.25 设置 HTTP
版本
可解决一些 HTTP
和 HTTPS
请求问题。
var res = await "http://furion.baiqian.ltd".SetHttpVersion("1.0").GetAsync(); // Furion 4.8.5.8+ 支持
19.4.26 下载远程文件并保存
以下内容仅限 Furion 4.8.7.32 +
版本使用。
await "http://furion.baiqian.ltd/img/rm1.png".GetToSaveAsync("D:/rm3.png");
await "http://furion.baiqian.ltd/img/rm1.png".PostToSaveAsync("D:/rm3.png");
...
19.5 IHttpDispatchProxy
代理方式
19.5.1 支持多种代理方式
public interface IHttp : IHttpDispatchProxy
{
// 发送 Get 请求
[Get("http://furion.baiqian.ltd/get")]
Task<HttpResponseMessage> GetXXXAsync();
// 发送 Post 请求
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync();
// 发送 Put 请求
[Put("http://furion.baiqian.ltd/put")]
Task<HttpResponseMessage> PutXXXAsync();
// 发送 Delete 请求
[Delete("http://furion.baiqian.ltd/delete")]
Task<HttpResponseMessage> DeleteXXXAsync();
// 发送 Patch 请求
[Patch("http://furion.baiqian.ltd/patch")]
Task<HttpResponseMessage> PatchXXXAsync();
// 发送 Head 请求
[Head("http://furion.baiqian.ltd/head")]
Task<HttpResponseMessage> HeadXXXAsync();
}
19.5.2 设置地址模板
public interface IHttp : IHttpDispatchProxy
{
[Get("http://furion.baiqian.ltd/get/{id}?name={name}&number={p.PersonDetail.PhonNumber}")]
Task<HttpResponseMessage> GetXXXAsync(int id, string name, Person p);
}
注:模板替换区分大小写。
19.5.3 设置请求报文头
Furion
框架远程请求代理模式提供三种方式设置请求报文头:
- 支持在接口中声明
- 支持在方法中声明
- 支持在参数中声明
[Headers("key","value")]
[Headers("key1","value2")] // 设置多个
public interface IHttp : IHttpDispatchProxy
{
[Get("http://furion.baiqian.ltd/get/{id}?name={name}"), Headers("key2","value2")]
Task<HttpResponseMessage> GetXXXAsync(int id, string name);
[Get("http://furion.baiqian.ltd")]
Task<HttpResponseMessage> GetXXX2Async(int id, [Headers]string token = default);
[Get("http://furion.baiqian.ltd")]
Task<HttpResponseMessage> GetXXX2Async(int id, string name, [Headers("别名")]string token = default);
}
如需动态设置,可使用以下方式(添加参数拦截器):
public interface IHttp : IHttpDispatchProxy
{
// 通过参数拦截
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync(string name, [Interceptor(InterceptorTypes.Request)] Action<HttpClient, HttpRequestMessage> action = default);
}
调用:
_http.PostXXXAsync("百小僧", (client, requestMessage) =>
{
requestMessage.AppendHeaders(new Dictionary<string , object> {
{ "Authorization", "Bearer 你的token"},
{ "X-Authorization", "Bearer 你的刷新token"}
});
// 也支持对象,匿名方式
requestMessage.AppendHeaders(new {
Authorization = "Bearer 你的token",
Others = "其他"
});
// 也可以使用原生
requestMessage.Headers.TryAddWithoutValidation("Authorization", "Bearer 你的token");
requestMessage.Headers.TryAddWithoutValidation("key", "value");
});
19.5.4 设置 URL
地址参数
public interface IHttp : IHttpDispatchProxy
{
[Get("http://furion.baiqian.ltd/get/{id}?name={name}")]
Task<HttpResponseMessage> GetXXXAsync(int id, string name);
[Get("http://furion.baiqian.ltd/get/{p.Id}?name={p.Name}")]
Task<HttpResponseMessage> GetXXXAsync(Person p);
[Get("http://furion.baiqian.ltd/get")]
Task<HttpResponseMessage> GetXXXAsync([QueryString]int id, [QueryString]string name);
[Get("http://furion.baiqian.ltd/get")]
Task<HttpResponseMessage> GetXXXAsync([QueryString]int id, [QueryString("别名")]string name);
// Furion 4.8.1.4 新增 [QueryString(Format)] 配置时间类型格式化
[Get("http://furion.baiqian.ltd/get")]
Task<HttpResponseMessage> GetXXXAsync([QueryString(Format = "yyyy-MM-dd HH:mm:ss")] DateTime queryStartTime, [QueryString(Format = "yyyy-MM-dd HH:mm:ss")] DateTime queryEndTime);
// Furion 4.8.1.4 新增 [QueryString(Format)] 配置时间类型格式化
[Get("http://furion.baiqian.ltd/get")]
Task<HttpResponseMessage> GetXXXAsync([QueryString(Format = "yyyy-MM-dd HH:mm:ss")] DateTimeOffset queryStartTime, [QueryString(Format = "yyyy-MM-dd HH:mm:ss")] DateTimeOffset queryEndTime);
// Furion 4.7.3 新增 IgnoreNullValueQueries 配置忽略空值
[Get("http://furion.baiqian.ltd/get", IgnoreNullValueQueries = true)]
Task<HttpResponseMessage> GetXXXAsync([QueryString]int id, [QueryString]string name, [QueryString]string nullValue);
}
最终输出格式为:http://furion.baiqian.ltd/get?id=1&name=Furion
。
在对接某些第三方接口的时候可能遇到一种情况,需要把对象序列化或者进行某种处理后作为 Url
参数,如:
[Get("http://furion.baiqian.ltd/get?json={p}", WithEncodeUrl = false)] // 这里将 p 作为模板传入
Task<HttpResponseMessage> GetXXXAsync(Person p);
如果 Person
类型不做任何处理,那么最终传递的是 Person
的命名空间:http://furion.baiqian.ltd/get?json=YourProject.Person
,但这并非是我们的预期。
这个时候我们只需要重写 Person
的 ToString
方法即可,如:
public class Person
{
public string Name { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this); // 比如这里做序列化处理
// 如果基类中 override,可使用 return JsonSerializer.Serialize<object>(this);
}
}
19.5.5 设置请求客户端
- 全局配置方式
services.AddRemoteRequest(options=>
{
// 配置 Github 基本信息
options.AddHttpClient("github", c =>
{
c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});
});
[Client("github")] // 可以在接口中全局使用
public interface IHttp : IHttpDispatchProxy
{
[Get("get"), Client("github")] // 也可以在方法中局部使用
Task<HttpResponseMessage> GetXXXAsync();
}
最终生成请求地址为:https://api.github.com/get
。
- 局部配置方式
以下内容仅限 Furion 4.3.8 +
版本使用。
public interface IHttp : IHttpDispatchProxy
{
// 局部方式
[Get("get")]
Task<HttpResponseMessage> GetXXXAsync([Interceptor(InterceptorTypes.Initiate)]Func<HttpClient> clientProvider);
// 全局静态方式
[Interceptor(InterceptorTypes.Initiate)]
static HttpClient CreateHttpClient()
{
return new HttpClient(...);
}
}
19.5.6 设置 Body
参数
public interface IHttp : IHttpDispatchProxy
{
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Body]User user);
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Body("application/x-www-form-urlencoded")]User user);
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Body("application/x-www-form-urlencoded", "UTF-8")]User user);
}
19.5.7 设置 JSON
序列化提供程序
Furion
默认情况下采用 System.Text.Json
进行 JSON
序列化处理,如需设置第三方 JSON
提供器,则可以通过以下配置:
public interface IHttp : IHttpDispatchProxy
{
[Post("http://furion.baiqian.ltd/post"), JsonSerialization(typeof(NewtonsoftJsonSerializerProvider))]
Task<HttpResponseMessage> PostXXXAsync([Body]User user);
[Post("http://furion.baiqian.ltd/post"), JsonSerialization(typeof(NewtonsoftJsonSerializerProvider))]
Task<HttpResponseMessage> PostXXXAsync([Body]User user, [JsonSerializerOptions]object jsonSerializerOptions = default);
/// <summary>
/// 缺省序列化配置
/// </summary>
/// <returns></returns>
[JsonSerializerOptions]
static object GetJsonSerializerOptions()
{
// 这里也可以通过 JSON.GetSerializerOptions<JsonSerializerOptions>() 获取 Startup.cs 中的配置
return new JsonSerializerOptions
{
};
}
}
[JsonSerializerOptions]
可以标记参数是 一个 JSON
序列化配置参数。
JSON
序列化提供器如需了解更多 JSON
序列化知识可查阅 23. JSON 序列化 章节
19.5.8 参数验证
public interface IHttp : IHttpDispatchProxy
{
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Range(1,10)]int id, [Required, MaxLength(10)]string name);
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Required]User user); // 对象类型支持属性配置特性验证
}
19.5.9 请求拦截
Furion
远程请求代理方式提供两种拦截方式:
- 接口静态方法拦截
- 参数标记拦截
public interface IHttp : IHttpDispatchProxy
{
// 通过参数拦截
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Interceptor(InterceptorTypes.Request)] Action<HttpClient, HttpRequestMessage> action = default);
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Request)]
static void OnRequesting1(HttpClient client, HttpRequestMessage req)
{
// 追加更多参数
req.AppendQueries(new Dictionary<string, object> {
{ "access_token", "xxxx"}
});
}
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Request)]
static void OnRequesting2(HttpClient client, HttpRequestMessage req)
{
}
}
支持多次拦截
19.5.10 HttpClient
拦截
Furion
远程请求代理方式提供两种拦截方式:
- 接口静态方法拦截
- 参数标记拦截
public interface IHttp : IHttpDispatchProxy
{
// 通过参数拦截
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Interceptor(InterceptorTypes.Client)] Action<HttpClient> action = default);
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Client)]
static void onClientCreating1(HttpClient client)
{
}
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Client)]
static void onClientCreating2(HttpClient client)
{
}
}
支持多次拦截
19.5.11 请求之前拦截
Furion
远程请求代理方式提供两种拦截方式:
- 接口静态方法拦截
- 参数标记拦截
public interface IHttp : IHttpDispatchProxy
{
// 通过参数拦截
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Interceptor(InterceptorTypes.Request)] Action<HttpClient, HttpRequestMessage> action = default);
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Request)]
static void OnRequest1(HttpClient client, HttpRequestMessage req)
{
}
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Request)]
static void OnRequest2(HttpClient client, HttpRequestMessage req)
{
}
}
支持多次拦截
19.5.12 成功请求拦截
Furion
远程请求代理方式提供两种拦截方式:
- 接口静态方法拦截
- 参数标记拦截
public interface IHttp : IHttpDispatchProxy
{
// 通过参数拦截
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Interceptor(InterceptorTypes.Response)] Action<HttpClient, HttpResponseMessage> action = default);
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Response)]
static void OnResponsing1(HttpClient client, HttpResponseMessage res)
{
}
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Response)]
static void OnResponsing2(HttpClient client, HttpResponseMessage res)
{
}
}
支持多次拦截
19.5.13 请求异常拦截
Furion
远程请求代理方式提供两种拦截方式:
- 接口静态方法拦截
- 参数标记拦截
public interface IHttp : IHttpDispatchProxy
{
// 通过参数拦截
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync([Interceptor(InterceptorTypes.Exception)] Action<HttpClient, HttpResponseMessage, string> action = default);
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Exception)]
static void OnException1(HttpClient client, HttpResponseMessage res, string errors)
{
}
// 全局拦截,类中每一个方法都会触发
[Interceptor(InterceptorTypes.Exception)]
static void OnException2(HttpClient client, HttpResponseMessage res, string errors)
{
}
}
支持多次拦截
19.5.14 各种返回值处理
Furion
远程请求默认 提供四种返回值类型:
HttpResponseMessage
:请求响应消息类型Stream
:流类型,可用来下载文件T
:泛型T
类型String
:字符串类型,也就是直接将网络请求结果内容字符串化
如:
public interface IHttp : IHttpDispatchProxy
{
// HttpResponseMessage
[Post("http://furion.baiqian.ltd/post")]
Task<HttpResponseMessage> PostXXXAsync();
// Stream,可用来下载文件
[Post("http://furion.baiqian.ltd/post")]
Task<Stream> PostXXXAsync();
// T
[Post("http://furion.baiqian.ltd/post")]
Task<User> PostXXXAsync();
// String
[Post("http://furion.baiqian.ltd/post")]
Task<string> PostXXXAsync();
}
19.5.15 设置 Byte[]/Stream
类型/上传文件
Furion 4.4.0
以下版本在 Furion 4.4.0+
版本移除了 [BodyBytes]
方式,原因是拓展性太差,