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

Flutter集成FCM推送调用v1接口返回401错误求助

FCM HTTP v1接口调用返回401错误的解决方法

问题描述

在Flutter应用中集成FCM推送时,调用FCM HTTP v1接口返回401认证错误,无法正常发送推送。当前实现的sendPushMessage函数代码如下:

void sendPushMessage(String token, String body, String title) async {
  Dio dio = Dio();
  try {
    await dio.post(
        'https://fcm.googleapis.com/v1/projects/ecommerece-c1601/messages:send',
        options: Options(
          headers: {
            "Authorization": "Bearer ${ApiKeys.fcmServerKey}",
            "Content-Type": "application/json"
          },
        ),
        data: {
          "priority": "high",
          "data": {
            "click_action": "FLUTTER_NOTIFICATION_CLICK",
            "status": "done",
            "body": body,
            "title": title,
          },
          "message": {
            "token": token,
            "notification": {
              "title": title,
              "body": body,
              "android_channel_id": "Shoppie"
            }
          },
          "android": {
            "notification": {"click_action": "TOP_STORY_ACTIVITY"}
          },
          "apns": {
            "payload": {
              "aps": {"category": "NEW_MESSAGE_CATEGORY"}
            }
          }
        });
  } catch (e) {
    print("error");
    log(e.toString());
  }
}

已完成的配置:

  • 按FCM从Legacy API迁移到HTTP v1的文档配置了接口地址,ecommerece-c1601为项目ID
  • 在Firebase和Google Cloud API服务中启用了FCM API
  • 环境变量中配置了GOOGLE_APPLICATION_CREDENTIALS,对应Firebase项目设置中的私钥
  • 已启用Cloud Messaging API (Legacy),代码中使用了对应的Server Key

返回的错误信息:

[log] DioException [bad response]: This exception was thrown because the response has a status code of 401 and RequestOptions.validateStatus was configured to throw for this status code.
The status code of 401 has the following meaning: "Client error - the request contains bad syntax or cannot be fulfilled"
Read more about status codes at https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
In order to resolve this exception you typically have either to verify and fix your request code or you have to fix the server code.

解决方法

1. 核心问题:认证方式错误

FCM HTTP v1接口不支持Legacy Server Key,必须使用Google OAuth2访问令牌。你当前用Legacy Server Key作为Bearer令牌,这是导致401错误的根本原因。

2. 生成OAuth2访问令牌

使用googleapis_auth包生成短期的FCM访问令牌,步骤如下:

首先在pubspec.yaml添加依赖:

dependencies:
  googleapis_auth: ^1.4.1
  http: ^1.1.0
  dio: ^5.3.0 # 确保dio版本兼容

然后实现获取令牌的函数:

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:googleapis_auth/auth_io.dart';
import 'package:http/http.dart' as http;

Future<String> getFcmAccessToken() async {
  final serviceAccountPath = Platform.environment['GOOGLE_APPLICATION_CREDENTIALS'];
  if (serviceAccountPath == null) {
    throw Exception("GOOGLE_APPLICATION_CREDENTIALS环境变量未配置");
  }
  
  final serviceAccountJson = json.decode(File(serviceAccountPath).readAsStringSync());
  final serviceAccount = ServiceAccountCredentials.fromJson(serviceAccountJson);
  
  final scopes = ['https://www.googleapis.com/auth/firebase.messaging'];
  
  final client = await clientViaServiceAccount(serviceAccount, scopes);
  final accessToken = client.credentials.accessToken.data;
  client.close();
  
  return accessToken;
}

3. 修改推送函数

更新sendPushMessage函数,替换认证头,同时修正请求数据结构(v1接口要求data、android、apns等字段嵌套在message对象内):

import 'package:dio/dio.dart';
import 'dart:developer' as dev;

void sendPushMessage(String token, String body, String title) async {
  Dio dio = Dio();
  try {
    final fcmToken = await getFcmAccessToken();
    await dio.post(
      'https://fcm.googleapis.com/v1/projects/ecommerece-c1601/messages:send',
      options: Options(
        headers: {
          "Authorization": "Bearer $fcmToken",
          "Content-Type": "application/json"
        },
      ),
      data: {
        "message": {
          "token": token,
          "notification": {
            "title": title,
            "body": body,
            "android_channel_id": "Shoppie"
          },
          "data": {
            "click_action": "FLUTTER_NOTIFICATION_CLICK",
            "status": "done",
            "body": body,
            "title": title,
          },
          "android": {
            "notification": {"click_action": "TOP_STORY_ACTIVITY"}
          },
          "apns": {
            "payload": {
              "aps": {"category": "NEW_MESSAGE_CATEGORY"}
            }
          }
        },
        "priority": "high"
      },
    );
    print("推送发送成功");
  } catch (e) {
    print("推送发送失败");
    dev.log(e.toString());
  }
}

4. 额外检查项

  • 确认服务账号拥有Firebase Cloud Messaging Admin角色:在Google Cloud控制台的IAM页面,找到对应服务账号,添加Firebase Cloud Messaging Admin角色
  • 验证项目IDecommerece-c1601与Firebase项目的实际ID一致
  • 确保服务账号密钥文件未过期,且配置的环境变量路径正确

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 19:16:22