You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebAssembly新手求助:登录提交后页面刷新无法捕获HttpClient响应

登录页面自动刷新,无法展示HttpClient响应提示信息

我是WebAssembly新手,输入登录凭据后,登录页面总是自动刷新,导致无法测试HttpClient的响应。执行到var authResult = await _httpClient.PostAsync("api/Login", bodyContent);这行代码后,页面就会刷新初始化,无法展示服务器离线、凭据错误等提示信息。以下是我的相关代码:

program.cs

var apiUrl = new Uri(configuration["apiUrl"]);

//builder.Services.AddTransient<SkyPulsarAuthorizationMessageHandler>();

builder.Services.AddHttpClient("EdiRPX", httpClient =>
{
    httpClient.BaseAddress = apiUrl;  
})
    .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
    {
        TimeSpan.FromSeconds(1),
        TimeSpan.FromSeconds(5)
    }));
//.AddHttpMessageHandler<SkyPulsarAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("EdiRPX"));
builder.Services.AuthClientSetup();
//*
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
//*
builder.Services.AddSingleton<SignalRClientService>();
builder.Services.AddTransient<IHelloService, HelloService>();
builder.Services.AddOidcAuthentication(options =>
{
    // Configure your authentication provider options here.
    // For more information, see https://aka.ms/blazor-standalone-auth
    builder.Configuration.Bind("Local", options.ProviderOptions);
    options.ProviderOptions.DefaultScopes.Add(builder.Configuration["apiUrl"]);
});

await builder.Build().RunAsync();

Login.razor.cs的提交处理

public partial class Login
    {
        private string? hello { get; set; }
        public IEnumerable<string> Errors { get; set; }
        private LoginModel model = new LoginModel();
        string backgroundUrl = "./resources/bg02.jpg";
        private LoginResult user;
        private bool loading;
        private bool ShowErrors;
        private bool ShowHello;
        [CascadingParameter]
        public Error? Error { get; set; }


        protected override void OnInitialized()
        {
            // redirect to home if already logged in            
            backgroundUrl = "./resources/bg02.jpg";
            StateHasChanged();
        }

        public Login()
        {
            user = new LoginResult();

        }

        private void ChangeBackground()
        {
            backgroundUrl = "./resources/2.jpg";
            StateHasChanged();
        }

        private async void HandleValidSubmit()
        {
            loading = true;
            ShowErrors = false;
            try
            {
                //hello = await helloService.Run();
                //ShowHello = true;
                //loading = false;
                user = await AuthService.Login(model);
                //var returnUrl = navigationManager.QueryString("returnUrl") ?? "";
                //navigationManager.NavigateTo(returnUrl);
                if (user.Success)
                {
                    navigationManager.NavigateTo("/");
                }
                else
                {
                    Errors = user.Errors;
                    ShowErrors = true;
                    //StateHasChanged();
                }
            }
            catch (Exception ex)
            {
                Error?.ProcessError(ex);
                //ShowErrors = true;
                //Errors = new[] { ex.Message };
                loading = false;
                //StateHasChanged();
            }
        }

    }
}

处理HttpClient请求的AuthService

public async Task<LoginResult> Login(LoginModel loginModel)
        {            

            var content = JsonSerializer.Serialize(loginModel);
            var bodyContent = new StringContent(content, Encoding.UTF8, "application/json");
            var _httpClient = _httpFactory.CreateClient("EdiRPX");
            var loginResult = new LoginResult();
            try
            {
                var authResult = await _httpClient.PostAsync("api/Login", bodyContent);
                if (!authResult.IsSuccessStatusCode)
                {
                    ;
                    loginResult.Errors = new List<string>()
                    {
                        authResult.StatusCode.ToString()
                    };
                    loginResult.Success = false;
                    return loginResult;
                }
                var authContent = await authResult.Content.ReadAsStringAsync();
                loginResult = JsonSerializer.Deserialize<LoginResult>(authContent, _options);

                await _localStorage.SetItemAsync("authToken", loginResult.Token);
                ((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(loginModel.Email);
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", loginResult.Token);
                loginResult.Success = true;
                return loginResult;
            }
            catch (Exception ex)
            {
                if (loginResult != null)
                {
                    loginResult.Errors = new List<string>()
                    {
                        ex.Message
                    };
                    loginResult.Success = false;
                    return loginResult;
                }
                else
                {
                    return new LoginResult();
                }

            }
            //StateHasChanged();
        }

问题分析与解决方法

核心错误:异步事件处理方法使用async void

HandleValidSubmit方法定义为async void,这是Blazor组件异步事件处理的典型错误。async void会让Blazor框架无法追踪异步操作的执行状态,当异步代码(比如HttpClient请求)开始执行后,框架无法等待其完成,可能触发页面意外刷新,导致后续的错误提示逻辑无法执行。

修正方案

将async void改为async Task,Blazor完全支持返回Task的异步事件处理方法,这样框架能正确等待异步操作完成,确保后续UI更新逻辑正常执行:

private async Task HandleValidSubmit()
{
    loading = true;
    ShowErrors = false;
    try
    {
        user = await AuthService.Login(model);
        if (user.Success)
        {
            navigationManager.NavigateTo("/");
        }
        else
        {
            Errors = user.Errors;
            ShowErrors = true;
        }
    }
    catch (Exception ex)
    {
        Error?.ProcessError(ex);
        ShowErrors = true;
        Errors = new[] { ex.Message };
    }
    finally
    {
        loading = false; // 确保无论请求成功/失败都重置加载状态
        StateHasChanged(); // 手动通知组件更新UI
    }
}

额外注意事项

  1. 确保Login.razor中的表单使用EditForm组件并绑定OnValidSubmit="HandleValidSubmit",EditForm会自动阻止原生表单的默认提交行为,避免页面刷新。
  2. AuthService中每次创建新的HttpClient实例后设置的Authorization头,仅对当前实例有效。如果需要全局生效,建议通过自定义HttpMessageHandler实现,或者在ApiAuthenticationStateProvider中维护全局的认证令牌。

内容的提问来源于stack exchange,提问作者João Rodrigues

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:10:36