配置简介
Flurl.Http行为可通过一个分层设置系统进行配置,每一层按如下配置顺序继承/覆盖前一层:
- FlurlHttp.GlobalSettings (静态的)
- IFlurlClient.Settings
- IFlurlRequest.Settings
- HttpTest.Settings (配置的测试参数总是有效性最高)
所有4个级别的可用属性大多相同,只有少数例外。下面是一个完整的列表,包括它们的位置和不支持的位置:
Property | FlurlHttp (global) | HttpTest | IFlurlClient | IFlurlRequest |
---|---|---|---|---|
Timeout | x | x | x | x |
AllowedHttpStatusRange | x | x | x | x |
JsonSerializer | x | x | x | x |
UrlEncodedSerializer | x | x | x | x |
Redirects | x | x | x | x |
BeforeCall | x | x | x | x |
BeforeCallAsync | x | x | x | x |
AfterCall | x | x | x | x |
AfterCallAsync | x | x | x | x |
OnError | x | x | x | x |
OnErrorAsync | x | x | x | x |
OnRedirect | x | x | x | x |
OnRedirectAsync | x | x | x | x |
ConnectionLeaseTimeout | x | x | x | |
HttpClientFactory | x | x | x | |
FlurlClientFactory | x |
请注意,只有没有显式地设置值时,才表示要从层次结构的上层继承。null的意思是null,而不是继承。
配置设置
设置属性都是可读/写的,但如果你想一次(原子地)改变多个配置参数,你通常应该用一个Configure*
方法来做,它使用Action<Settings>
委托。
配置全局默认值:
// 在用户程序启动时调用一次即可
FlurlHttp.Configure(settings => ...);
您还可以配置用于调用给定URL的FlurlClient。需要注意的是,在默认情况下同一个FlurlClient用于对同一主机的所有调用,所以这可能会影响到的不仅仅是对提供的特定URL的调用:
// 在用户程序启动时调用一次即可
FlurlHttp.ConfigureClient(url, cli => ...);
或者,你也可以显式地配置FlurlClient
:
flurlClient.Configure(settings => ...);
或者,链式地配置单个请求(通过字符串、Url或IFlurlRequest的扩展方法):
await url.ConfigureRequest(settings => ...).GetAsync();
还可以在测试中覆盖任何设置,无论这些设置在测试对象的哪个级别:
httpTest.Configure(settings => ...);
如果需要,你可以将任何级别的设置恢复为默认值或继承的值:
flurlClient.Settings.ResetDefaults();
FlurlHttp.GlobalSettings.ResetDefaults();
下面让我们来看看一些特定的设置。
HttpClientFactory
不要与.NET Core的
IHttpClientFactory
混淆;它们是非常不同的东西(Flurl的IHttpClientFactory比.NET Core的出现得早)。
对于高级场景,您可以自定义Flurl.Http构造HttpClient
和HttpMessageHandler
实例。尽管只需要实现Flurl.Http.Configuration.IHttpClientFactory
,但建议从DefaultHttpClientFactory
继承,并只在需要时扩展,如下:
public class MyCustomHttpClientFactory : DefaultHttpClientFactory
{
// 重写CreateHttpClient方法
public override HttpClient CreateHttpClient(HttpMessageHandler handler);
// 重写CreateMessageHandler方法
public override HttpMessageHandler CreateMessageHandler();
}
注册全局工厂:
FlurlHttp.Configure(settings => {
settings.HttpClientFactory = new MyCustomHttpClientFactory();
});
或者在单个FlurlClient
上配置:
var cli = new FlurlClient(BASE_URL).Configure(settings => {
settings.HttpClientFactory = new MyCustomHttpClientFactory();
});
FlurlClientFactory
IFlurlClientFactory
接口定义了一个方法Get(Url)
,该方法负责提供应该用于调用该Url的IFlurlClient
实例。在应用程序的生命周期内,默认实现了根据URL的主机/方案/端口的组合使用一个缓存的FlurlClient
实例。
要改变这种行为,你可以通过直接实现IFlurlClientFactory
来定义你自己的工厂,但是从FlurlClientFactoryBase
继承要容易得多。它允许您通过返回基于Url的缓存键来定义缓存策略,而不必实现缓存本身,如下:
public abstract class FlurlClientFactoryBase : IFlurlClientFactory
{
// 重写GetCacheKey方法
protected abstract string GetCacheKey(Url url);
// 重写Create方法(仅在需要时才调用此方法)
protected virtual IFlurlClient Create(Url url);
}
虽然FlurlClientFactory
配置设置仅在全局级别可用,但IFlurlClientFactory
在依赖注入模式时也很有用。
序列化
JsonSerializer和UrlEncodedSerializer都实现了ISerializer,这是一个简单的接口,用于将对象与字符串进行序列化。
public interface ISerializer
{
string Serialize(object obj);
T Deserialize<T>(string s);
T Deserialize<T>(Stream stream);
}
两者都有一个全局注册的默认实现,你可以替换它们,但不是必要的。默认的JsonSerializer
实现是NewtonsoftJsonSerializer
,正如您可能猜到的那样,它使用了一直流行的Json.NET序列化类库。你可以使用NewtonsoftJsonSerializer
来自定义序列化配置,如下:
FlurlHttp.Configure(settings => {
var jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ObjectCreationHandling = ObjectCreationHandling.Replace
};
settings.JsonSerializer = new NewtonsoftJsonSerializer(jsonSettings);
});
事件处理
将关注点(如日志记录和错误处理)与正常的逻辑流分离开,通常会使代码更加清晰。Flurl.Http为这些场景提供了一个事件模型。BeforeCall
,AfterCall
, OnError
, OnRedirect
以及它们的*Async
同名异步方法都在全局或客户端级别被定义,但如果需要的话,也可以在每个请求中定义。这些方法都采用了Action<HttpCall>
委托,FlurlCall
提供了你可以利用的关于调用的丰富细节:
public class FlurlCall
{
public IFlurlRequest Request { get; set; }
public HttpRequestMessage HttpRequestMessage { get; set; }
public IFlurlResponse Response { get; set; }
public HttpResponseMessage HttpResponseMessage { get; set; }
public string RequestBody { get; }
public FlurlRedirect Redirect { get; set; }
public FlurlCall RedirectedFrom { get; set; }
public Exception Exception { get; set; }
public bool ExceptionHandled { get; set; }
public DateTime StartedUtc { get; set; }
public DateTime? EndedUtc { get; set; }
public TimeSpan? Duration { get; }
public bool Completed { get; }
public bool Succeeded { get; }
}
与响应有关的属性值在BeforeCall
中都是null
,AfterCall
在请求成功或者失败时都会被触发,在OnError中将ExceptionHandled设置为true可以防止出现异常。下面是一个注册全局异步错误处理程序的示例:
private async Task HandleFlurlErrorAsync(HttpCall call) {
await LogErrorAsync(call.Exception.Message);
call.ExceptionHandled = true;
}
FlurlHttp.Configure(settings => settings.OnErrorAsync = HandleFlurlErrorAsync);
重定向(Redirects)
像HttpClient一样,Flurl默认自动跟随3xx重定向,但是Flurl公开的设置和钩子提供了更高级别的可配置性,如下:
FlurlHttp.Configure(settings => {
settings.Redirects.Enabled = true; // 默认值:true
settings.Redirects.AllowSecureToInsecure = true; // 默认值:false
settings.Redirects.ForwardAuthorizationHeader = true; // 默认值:false
settings.Redirects.MaxAutoRedirects = 5; // 默认值:10 (连续的)
});
你还可以使用事件处理程序在每次调用的基础上配置重定向行为:
flurlClient.OnRedirect(call => {
if (call.Redirect.Count > 5) {
call.Redirect.Follow = false;
}
else {
log.WriteInfo($"redirecting from {call.Request.Url} to {call.Redirect.Url}");
call.Redirect.ChangeVerbToGet = (call.Response.Status == 301);
call.Redirect.Follow = true;
}
});
如果你只需要启用/禁用单个调用的自动重定向,你可以内联执行:
await url.WithAutoRedirect(false).GetAsync();
发表评论
登录用户才能发表评论, 请 登 录 或者 注册