Blazor WASM - Global Catch 401 并导航到所有 HttpClient 调用的登录页面
Blazor WASM - Global Catch 401 and navigate to login page on all HttpClient calls
在blazor template httpclient
中添加在Program.cs class
中:
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
以后使用如下:
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
有什么方法可以重写该基础 httpclient 并将其注入我的所有页面,这将:
- 在任何服务器请求(post/get 等)中捕获 401 returned
- 尝试刷新令牌(为此调用 API)
- return刷新失败时登录
我看到我可以定义一个自定义服务来包装所有这些 HTTP 客户端调用并执行我提到的操作,但是有没有更好的方法来做到这一点?
如果您想通过 HttpClient 拦截所有调用,那么您需要创建一个允许您进行 HttpCalls 的服务,这样您就可以在其中拦截它们并使用 HttpClient。
PS:您应该将任何实现 IDisposable 的 class(例如 HttpClient)的注册从 Transient 更改为 Scoped。这将在未来的 Blazor 模板中改变。
- 使用处理 401 响应代码创建自定义
DelegatingHandler
。
public class CustomMessageHandler : DelegatingHandler
{
private readonly string host;
readonly NavigationManager _navigationManager;
CustomMessageHandler(IWebAssemblyHostEnvironment webAssemblyHostEnvironment, navigationManager)
{
host = webAssemblyHostEnvironment.BaseAddress;
_navigationManager = navigationManager;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine("CustomMessageHandler catch 401");
// TODO: some logic (e.g. refreshing token)
// Or just redirect to login page.
string loingUrl = "http://some-site/login";
_navigationManager.NavigateTo(loingUrl, forceLoad: true);
}
return response;
}
}
- 在 IServiceCollection 中注册创建 CustomMessageHandler(在 blazor.Client 项目中)
builder.Services.AddScoped<CustomMessageHandler>();
- 同时使用我们的 CustomMessageHandler 注册已配置的 httpClient(在 blazor.Client 项目中)。
.AddHttpClient
需要 Microsoft.Extensions.Http
nuget 包。
builder.Services.AddHttpClient("BlazorServerHttpClient",
client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<CustomMessageHandler>();
- 从 blazor.Client 到 blazor.Server 的所有 httpClient 请求都必须像这样使用 IHttpClientFactory:
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
public class WeatherService
{
private readonly IHttpClientFactory _clientFactory;
public WeatherService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<WeatherForecast[]> GetWeatherForecast()
{
var client = _clientFactory.CreateClient("BlazorServerHttpClient");
WeatherForecast[] result = await client.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
return result;
}
}
在blazor template httpclient
中添加在Program.cs class
中:
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
以后使用如下:
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
有什么方法可以重写该基础 httpclient 并将其注入我的所有页面,这将:
- 在任何服务器请求(post/get 等)中捕获 401 returned
- 尝试刷新令牌(为此调用 API)
- return刷新失败时登录
我看到我可以定义一个自定义服务来包装所有这些 HTTP 客户端调用并执行我提到的操作,但是有没有更好的方法来做到这一点?
如果您想通过 HttpClient 拦截所有调用,那么您需要创建一个允许您进行 HttpCalls 的服务,这样您就可以在其中拦截它们并使用 HttpClient。
PS:您应该将任何实现 IDisposable 的 class(例如 HttpClient)的注册从 Transient 更改为 Scoped。这将在未来的 Blazor 模板中改变。
- 使用处理 401 响应代码创建自定义
DelegatingHandler
。
public class CustomMessageHandler : DelegatingHandler
{
private readonly string host;
readonly NavigationManager _navigationManager;
CustomMessageHandler(IWebAssemblyHostEnvironment webAssemblyHostEnvironment, navigationManager)
{
host = webAssemblyHostEnvironment.BaseAddress;
_navigationManager = navigationManager;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
Console.WriteLine("CustomMessageHandler catch 401");
// TODO: some logic (e.g. refreshing token)
// Or just redirect to login page.
string loingUrl = "http://some-site/login";
_navigationManager.NavigateTo(loingUrl, forceLoad: true);
}
return response;
}
}
- 在 IServiceCollection 中注册创建 CustomMessageHandler(在 blazor.Client 项目中)
builder.Services.AddScoped<CustomMessageHandler>();
- 同时使用我们的 CustomMessageHandler 注册已配置的 httpClient(在 blazor.Client 项目中)。
.AddHttpClient
需要Microsoft.Extensions.Http
nuget 包。
builder.Services.AddHttpClient("BlazorServerHttpClient",
client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<CustomMessageHandler>();
- 从 blazor.Client 到 blazor.Server 的所有 httpClient 请求都必须像这样使用 IHttpClientFactory:
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
public class WeatherService
{
private readonly IHttpClientFactory _clientFactory;
public WeatherService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<WeatherForecast[]> GetWeatherForecast()
{
var client = _clientFactory.CreateClient("BlazorServerHttpClient");
WeatherForecast[] result = await client.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
return result;
}
}