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

Blazor Server(.NET6)调用FCM API多次请求报401未授权问题排查

问题

我正在开发基于.NET 6的Blazor Server应用,需要通过Google Cloud Messaging(FCM)API发送通知。首次HTTP调用正常,但第二次调用时收到“401 Unauthorized”错误。使用Postman调用相同密钥可多次请求无问题,请问该问题的原因是什么?如何解决以实现无需重启页面即可多次调用?

发送通知的函数代码

private async Task SendNotification()
{
    var request = new HttpRequestMessage(HttpMethod.Post, "https://fcm.googleapis.com/fcm/send");
    http.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", key);

    string mensajeJSON = $@"{{
            ""data"": {{
                ""WX_PUSH_EXT_VERSION"":""1.0"",
                ""WX_PROP_TITRE"":""{NuevosDatos.Titulo}"",
                ""WX_PROP_MESSAGE"":""{NuevosDatos.Msg}"",
                ""WX_PROP_PRIORITE"":4,
                ""WX_PROP_ACTIVEAPPLICATION"":true,
                ""title"" : ""{NuevosDatos.Titulo}"",
                ""body"" : ""{NuevosDatos.Msg}"",
                ""priority"" : ""high""
            }},
            ""to"": ""/topics/{selelectedId.Name}""
            }}";

    request.Content = new StringContent(mensajeJSON, Encoding.UTF8, "application/json");
    var response = await http.SendAsync(request);
    response.EnsureSuccessStatusCode();
    await response.Content.ReadAsStringAsync();
    //NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
}

表单提交代码(Syncfusion组件)

<EditForm Model="NuevosDatos" OnValidSubmit="@EnviarDatos" OnInvalidSubmit="@MostrarMsgError">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div class="p-4 rounded-lg shadow-md max-w-md mx-auto">

        <div class="mb-4">
            <label class="block text-gray-700 font-bold mb-2">Titulo</label>
            <SfTextBox Placeholder="Introducir Titulo" @bind-Value="@NuevosDatos.Titulo"></SfTextBox>

        </div>

        <div class="mb-4">
            <label class="block text-gray-700 font-bold mb-2">Mensaje</label>
            <SfTextBox Placeholder="Introducir mensaje" Multiline="true" @bind-Value="@NuevosDatos.Msg"></SfTextBox>

        </div>

        <div class="mb-4">
            <label class="block text-gray-700 font-bold mb-2">Elige un tema</label>
            <InputSelect class="w-40" @bind-Value="NuevosDatos.TopicId">
                <option disabled selected>Elige</option>
                @foreach (var topic in listaTopics)
                {
                    <option value="@topic.Id">@topic.Name</option>
                }
            </InputSelect>
        </div>
        <SfToast @ref="ToastObj" CssClass="@toastClass" Content="@toastContent" TimeOut="@toastDuration">
            <ToastPosition X="Right" Y="Top"></ToastPosition>
        </SfToast>
        <div class="flex justify-end">
            <SfButton type="submit" class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">Submit</SfButton>
        </div>
    </div>
</EditForm>

原因分析与解决方案

原因

问题出在你将FCM的授权头(Authorization)添加到了**HttpClient的全局默认请求头(DefaultRequestHeaders)**中,而非当前请求的HttpRequestMessage专属头里:

  • 如果HttpClient是复用的(比如Scoped/单例注入),第一次调用时成功添加头,第二次调用TryAddWithoutValidation会因为头已存在而跳过添加。
  • Blazor Server的组件生命周期和HttpClient的连接复用机制可能导致全局头出现异常(比如头被意外覆盖、失效),从而触发FCM的401校验。
  • 全局添加请求头违反了请求隔离原则,容易引发跨请求的头污染问题。

解决方案

修改SendNotification函数,将授权头添加到当前请求的HttpRequestMessage Headers中,而非HttpClient的全局默认头:

private async Task SendNotification()
{
    var request = new HttpRequestMessage(HttpMethod.Post, "https://fcm.googleapis.com/fcm/send");
    // 把授权头添加到当前请求的Headers中,而非HttpClient全局头
    request.Headers.TryAddWithoutValidation("Authorization", key);

    string mensajeJSON = $@"{{
            ""data"": {{
                ""WX_PUSH_EXT_VERSION"":""1.0"",
                ""WX_PROP_TITRE"":""{NuevosDatos.Titulo}"",
                ""WX_PROP_MESSAGE"":""{NuevosDatos.Msg}"",
                ""WX_PROP_PRIORITE"":4,
                ""WX_PROP_ACTIVEAPPLICATION"":true,
                ""title"" : ""{NuevosDatos.Titulo}"",
                ""body"" : ""{NuevosDatos.Msg}"",
                ""priority"" : ""high""
            }},
            ""to"": ""/topics/{selelectedId.Name}""
            }}";

    request.Content = new StringContent(mensajeJSON, Encoding.UTF8, "application/json");
    var response = await http.SendAsync(request);
    response.EnsureSuccessStatusCode();
    await response.Content.ReadAsStringAsync();
}

额外检查项

  1. 确认你的key格式符合FCM要求,必须是"key=AAAAXXX..."的形式(前缀key=不能省略)。
  2. 确保HttpClient的生命周期配置合理:Blazor Server中推荐使用Scoped或Transient生命周期的HttpClient,避免单例带来的状态共享问题。

内容的提问来源于stack exchange,提问作者Gegob

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 12:37:56