Flurl.Http-3.2.4 升級到 4.0.0 版本后,https請求異常:Call failed. The SSL connection could not be established.
如下圖:
Flurl.Http-3.2.4版本繞過https的代碼,對于 Flurl.Http-4.0.0 版本來說方法不再適用,3.2.4及4.0.0版本繞過https代碼成果在文章最后有展示。
查看了Flurl.Http4.0的文檔,地址:Configuration - Flurl
配置相關(guān)文檔內(nèi)容簡單翻譯(翻譯可能不夠精準(zhǔn),請點(diǎn)擊上面鏈接查看官方文檔)如下:
配置
Flurl.Http 包含一組強(qiáng)大的選項(xiàng)和技術(shù),用于在各個(gè)級別配置其行為。
設(shè)置
Flurl 主要通過 Settings上可用的屬性進(jìn)行配置。以下是可用的設(shè)置:IFlurlClient IFlurlRequest IFlurlClientBuilder HttpTest
Setting | Type | Default Value |
---|---|---|
Timeout | TimeSpan? | 100 seconds |
HttpVersion | string | "1.1" |
AllowedHttpStatusRange | string | null ("2xx,3xx", effectively) |
Redirects.Enabled | bool | true |
Redirects.AllowSecureToInsecure | bool | false |
Redirects.ForwardHeaders | bool | false |
Redirects.ForwardAuthorizationHeader | bool | false |
Redirects.MaxAutoRedirects | int | 10 |
JsonSerializer | ISerializer | DefaultJsonSerializer |
UrlEncodedSerializer | ISerializer | UrlEncodedSerializer |
所有屬性都是讀/寫的,可以直接設(shè)置:
// set default on the client:
var client = new FlurlClient("https://some-api.com");
client.Settings.Timeout = TimeSpan.FromSeconds(600);
client.Settings.Redirects.Enabled = false;
// override on the request:
var request = client.Request("endpoint");
request.Settings.Timeout = TimeSpan.FromSeconds(1200);
request.Settings.Redirects.Enabled = true;
您還可以流暢地配置它們:
clientOrRequest.WithSettings(settings => {
? ? settings.Timeout = TimeSpan.FromSeconds(600);
? ? settings.AllowedHttpStatusRange = "*";
? ? settings.Redirects.Enabled = false;
})...
或者在很多情況下甚至更流利:
clientOrRequest
? ? .WithTimeout(600)
? ? .AllowAnyHttpStatus()
? ? .WithAutoRedirect(false)
? ? ...
當(dāng)同時(shí)使用客戶端、請求和流暢配置時(shí),您需要密切關(guān)注正在配置的對象,因?yàn)樗梢源_定對該客戶端的后續(xù)調(diào)用是否受到影響:
await client
? ? .WithSettings(...) // configures the client, affects all subsequent requests
? ? .Request("endpoint") // creates and returns a request
? ? .WithSettings(...) // configures just this request
? ? .GetAsync();
無客戶端模式支持所有相同的擴(kuò)展方法。配置并發(fā)送請求而無需顯式引用客戶端:
var result = await "https://some-api.com/endpoint"
? ? .WithSettings(...) // configures just this request
? ? .WithTimeout(...) // ditto
? ? .GetJsonAsync<T>();
上述所有設(shè)置和擴(kuò)展方法也可以在 上使用IFlurlClientBuilder,這對于在啟動(dòng)時(shí)進(jìn)行配置非常有用:
// clientless pattern, all clients:
FlurlHttp.Clients.WithDefaults(builder =>
? ? builder.WithSettings(...));
// clientless pattern, for a specific site/service:
FlurlHttp.ConfigureClientForUrl("https://some-api.com")
? ? .WtihSettings(...);
// DI pattern:
services.AddSingleton<IFlurlClientCache>(_ => new FlurlClientCache()
? ? // all clients:
? ? .WithDefaults(builder =>
? ? ? ? builder.WithSettings(...))
? ? // specific named client:
? ? .Add("MyClient", "https://some-api.com", builder =>
? ? ? ? builder.WithSettings(...))
Settings支持(以及所有相關(guān)的流暢優(yōu)點(diǎn))的第四個(gè)也是最后一個(gè)對象是HttpTest,并且它優(yōu)先于所有內(nèi)容:
using var test = new HttpTest.AllowAnyHttpStatus();
await sut.DoThingAsync(); // no matter how things are configured in the SUT,
? ? ? ? ? ? ? ? ? ? ? ? ? // test settings always win?
序列化器
和設(shè)置值得特別注意JsonSerializer。UrlEncodedSerializer正如您所料,它們分別控制(反)序列化 JSON 請求和響應(yīng)以及 URL 編碼的表單帖子的詳細(xì)信息。兩者都實(shí)現(xiàn)了ISerializer,定義了 3 個(gè)方法:
string Serialize(object obj);
T Deserialize<T>(string s);
T Deserialize<T>(Stream stream);
Flurl 為兩者提供了默認(rèn)實(shí)現(xiàn)。您不太可能需要使用不同的UrlEncodedSerializer,但您可能出于以下幾個(gè)原因想要更換JsonSerializer:
-
您更喜歡3.x 及更早版本的基于Newtonsoft的版本。(4.0 將其替換為基于System.Text.Json的版本。)這可以通過 Flurl.Http.Newtsonsoft配套包獲得。
-
您想要使用默認(rèn)實(shí)現(xiàn),但使用自定義JsonSerializerOptions。這可以通過提供您自己的實(shí)例來完成:
clientOrRequest.Settings.JsonSerializer = new DefaultJsonSerializer(new JsonSerializerOptions {
PropertyNameCaseInsensitive = true,
IgnoreReadOnlyProperties = true
});
事件處理程序
將日志記錄和錯(cuò)誤處理等橫切關(guān)注點(diǎn)與正常邏輯流程分開通常會產(chǎn)生更清晰的代碼。Flurl.Http 定義了 4 個(gè)事件 - BeforeCall、AfterCall、OnError和OnRedirect- 以及、和EventHandlers上的集合。(與 不同,事件處理程序在 上不可用。)IFlurlClient IFlurlRequest IFlurlClientBuilder Settings HttpTest
與 類似Settings,所有具有EventHandlers屬性的東西都會帶來一些流暢的快捷方式:
clientOrRequest
.BeforeCall(call => DoSomething(call)) // attach a synchronous handler
.OnError(call => LogErrorAsync(call)) // attach an async handler
在上面的示例中,call是 的一個(gè)實(shí)例FlurlCall,其中包含與請求和響應(yīng)的各個(gè)方面相關(guān)的一組可靠的信息和選項(xiàng):
IFlurlRequest Request
HttpRequestMessage HttpRequestMessage
string RequestBody
IFlurlResponse Response
HttpResponseMessage HttpResponseMessage
FlurlRedirect Redirect
Exception Exception
bool ExceptionHandled
DateTime StartedUtc
DateTime? EndedUtc
TimeSpan? Duration
bool Completed
bool Succeeded
OnError在 之前觸發(fā)AfterCall,并讓您有機(jī)會決定是否允許異常冒泡:
clientOrRequest.OnError(async call => {
await LogTheErrorAsync(call.Exception);
call.ExceptionHandled = true; // otherwise, the exeption will bubble up
});
OnRedirect允許精確處理 3xx 響應(yīng):
clientOrRequest.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;
}
});
在較低級別,事件處理程序是實(shí)現(xiàn) 的對象IFlurlEventHandler,它定義了 2 個(gè)方法:
void Handle(FlurlEventType eventType, FlurlCall call);
Task HandleAsync(FlurlEventType eventType, FlurlCall call);
通常,您只需要實(shí)現(xiàn)一個(gè)或另一個(gè),因此 Flurl 提供了一個(gè)默認(rèn)實(shí)現(xiàn) ,F(xiàn)lurlEventHanler它構(gòu)成了一個(gè)方便的基類 - 兩種方法都是虛擬無操作的,因此只需重寫您需要的方法即可。處理程序可以這樣分配:
clientOrRequest.EventHandlers.Add((FlurlEventType.BeforeCall, new MyEventHandler()));
請注意,EventHanlers項(xiàng)目的類型為Tuple<EventType, IFlurlEventHandler>。保持處理程序與偶數(shù)類型分離意味著給定的處理程序可以重用于不同的事件類型。
您可能更喜歡基于對象的方法而不是前面描述的更簡單的基于 lambda 的方法,原因之一是如果您使用 DI 并且您的處理程序需要注入某些依賴項(xiàng):
public interface IFlurlErrorLogger : IFlurlEventHandler { }
public class FlurlErrorLogger : FlurlEventHandler, IFlurlErrorLogger
{
private readonly ILogger _logger;
public FlurlErrorLogger(ILogger logger) {
_logger = logger;
}
}
以下是如何使用 Microsoft 的 DI 框架進(jìn)行連接:
// register ILogger:
services.AddLogging();
// register service that implements IFlurlEventHander and has dependency on ILogger
services.AddSingleton<IFlurlErrorLogger, FlurlErrorLogger>();
// register event hanlder with Flurl, using IServiceProvider to wire up dependencies:
services.AddSingleton<IFlurlClientCache>(sp => new FlurlClientCache()
.WithDefaults(builder =>
builder.EventHandlers.Add((FlurlEventType.OnError, sp.GetService<IFlurlErrorLogger>()))
消息處理程序
Flurl.Http 構(gòu)建于 之上HttpClient,它(默認(rèn)情況下)使用它HttpClientHandler來完成大部分繁重的工作。IFlurlClientBuilder公開配置兩者的方法:
// clientless pattern:
FlurlHttp.Clients.WithDefaults(builder => builder
.ConfigureHttpClient(hc => ...)
.ConfigureInnerHandler(hch => {
hch.Proxy = new WebProxy("https://my-proxy.com");
hch.UseProxy = true;
}));
// DI pattern:
services.AddSingleton<IFlurlClientCache>(_ => new FlurlClientCache()
.WithDefaults(builder => builder.
.ConfigureHttpClient(hc => ...)
.ConfigureInnerHandler(hch => ...)));
溫馨提示:
1、Flurl 禁用AllowAutoRedirect和UseCookies以便重新實(shí)現(xiàn)自己的這些功能概念。如果您將 via 設(shè)置為 true ConfigureInnerHander,則可能會破壞 Flurl 中的這些功能。
2、DefaultRequestHeaders Flurl 還實(shí)現(xiàn)了自己的和概念Timeout,因此您可能不需要配置HttpClient.
也許您已經(jīng)閱讀過SocketsHttpHandler并且想知道如何在 Flurl 中使用它。您可能會驚訝地發(fā)現(xiàn)您可能已經(jīng)是這樣了。如前所述,FlurlClient
將其大部分工作委托給HttpClient
,而后者又將其大部分工作委托給HttpClientHandler
。但鮮為人知的是,自 .NET Core 2.1 以來,HttpClientHandler
幾乎將所有工作委托給SocketsHttpHandler
所有支持它的平臺,這基本上是除基于瀏覽器(即 Blazor)平臺之外的所有平臺。(如果需要說服力,請瀏覽源代碼。)?
FlurlClient → HttpClient → HttpClientHandler → SocketsHttpHandler (on all supported platforms)?
HttpClientHandler
盡管如此,您可能還是想繞過并直接使用,有一個(gè)原因SocketsHttpHander
:它的某些可配置性HttpClientHandler
在.?只要您不需要支持 Blazor,您就可以這樣做:?
// clientless pattern:
FlurlHttp.Clients.WithDefaults(builder =>
builder.UseSocketsHttpHandler(shh => {
shh.PooledConnectionLifetime = TimeSpan.FromMinutes(10);
...
}));
// DI pattern:
services.AddSingleton<IFlurlClientCache>(_ => new FlurlClientCache()
.WithDefaults(builder => builder.UseSocketsHttpHandler(shh => {
...
})));
注意:在同一構(gòu)建器上調(diào)用ConfigureInnerHandler和UseSocketsHttpHandler會導(dǎo)致運(yùn)行時(shí)異常。使用其中之一,切勿同時(shí)使用。
Flurl 直接支持的最后一種消息處理程序類型是DelegatingHandler,這是一種可鏈接的處理程序類型,通常稱為中間件,通常由第三方庫實(shí)現(xiàn)。
// clientless pattern:
FlurlHttp.Clients.WithDefaults(builder => builder
.AddMiddleare(new MyDelegatingHandler()));
// DI pattern:
services.AddSingleton<IFlurlClientCache>(sp => new FlurlClientCache()
.WithDefaults(builder => builder
.AddMiddleware(sp.GetService<IMyDelegatingHandler>())
此示例使用流行的彈性庫Polly以及在 DI 場景中配置 Flurl:
using Microsoft.Extensions.Http;
var policy = Policy
.Handle<HttpRequestException>()
...
services.AddSingleton<IFlurlClientCache>(_ => new FlurlClientCache()
.WithDefaults(builder => builder
.AddMiddleware(() => new PolicyHttpMessageHandler(policy))));
?上面的示例需要安裝Microsoft.Extensions.Http.Polly。
以上是配置相關(guān)的文檔,我并沒有在文檔中發(fā)現(xiàn)關(guān)于https的相關(guān)配置。
Flurl.Http-3.2.4版本繞過https證書代碼:
//Startup的ConfigureServices方法中配置
Flurl.Http.FlurlHttp.ConfigureClient(AppSettings.SFGZAPI.serversUrl, cli =>
? ? ? ? ? ? ? ? ? ? ? ? cli.Settings.HttpClientFactory = new UntrustedCertClientFactory());?
//此類建立你覺得方便的地方即可
public class UntrustedCertClientFactory : DefaultHttpClientFactory
{
? ? public override HttpMessageHandler CreateMessageHandler()
? ? {
? ? ? ? return new HttpClientHandler
? ? ? ? {
? ? ? ? ? ? ServerCertificateCustomValidationCallback = (a, b, c, d) => true
? ? ? ? };
? ? }
}
?對于4.0.0版本,經(jīng)過一番閱讀源代碼【https://github.com/tmenier/Flurl】并測試,測試如下圖:
上面截圖代碼均測試,依然還是:無法建立SSL連接。
又一次閱讀文檔無客戶端使用,發(fā)現(xiàn)FlurlHttp.UseClientCachingStrategy說明:
看到可以在這個(gè)方法中設(shè)置FlurlHttp,一直以為是配置,原來我自己進(jìn)入了坑,請閱讀管理客戶端相關(guān)文檔:Managing Clients - Flurl?或閱讀譯文:.NetCore Flurl.Http 4.0.0 以上管理客戶端-CSDN博客,于是開始了嘗試并可以正常訪問:
//無客戶端使用
FlurlHttp.UseClientCachingStrategy(request =>
{
FlurlHttp.Clients.GetOrAdd("https://xxx", "https://xxx", builder =>
builder
.ConfigureInnerHandler(hch =>
{
hch.ServerCertificateCustomValidationCallback = (a, b, c, d) => true;
}));
return "https://xxx";
});
測試:
/// <summary>
/// 無客戶端模式
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("FlurlHttp")]
public async Task<ActionResult> FlurlHttp()
{
try
{
var a = await "https://xxx"
.WithHeader("xx", "xxx")
.PostAsync()
.ReceiveJson<dynamic>();
return Ok(a);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
?還有依賴注入模式經(jīng)過測試也是可以的:
文章來源:http://www.zghlxwxcb.cn/news/detail-804226.html
希望本文對你有幫助。?文章來源地址http://www.zghlxwxcb.cn/news/detail-804226.html
到了這里,關(guān)于.NetCore Flurl.Http 升級到4.0后 https 無法建立SSL連接的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!