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

Flutter Desktop用Firebase Storage REST API传图片报Invalid Credentials错误

解决Firebase Storage REST API上传401认证错误

问题分析与修复步骤

1. Authorization头格式错误

你的代码中Authorization头末尾多了一个逗号:

"Authorization": "Bearer $token,"

这个多余的逗号会导致令牌格式无效,Firebase无法正确解析,必须删除逗号,改为:

"Authorization": "Bearer $token"

2. 请求数据错误

当前data参数传入的是文件路径字符串,而Firebase Storage的media上传需要直接传入文件的二进制数据。你需要读取文件字节后传入:

final fileBytes = await File(filePath).readAsBytes();
// ...
data: fileBytes,

3. Token获取方式错误

FirebaseAuth.instance.tokenProvider.idToken是一个Stream<String>,直接await无法正确获取令牌值。正确的方式是通过当前认证用户获取ID Token:

final user = FirebaseAuth.instance.currentUser;
if (user == null) {
  // 处理未登录情况
  throw Exception("User not authenticated");
}
final token = await user.getIdToken(true); // true表示强制刷新令牌,确保有效性

修正后的完整代码

Future<void> uploadProfilePicture({
  required String fileName,
  required String filePath,
  required String email,
}) async {
  return Chain.capture(() async {
    final url =
        "https://storage.googleapis.com/upload/storage/v1/b/${Constants.projectID}.appspot.com/o?uploadType=media&name=$email/profilePicture/$fileName";

    final fileBytes = await File(filePath).readAsBytes();
    final user = FirebaseAuth.instance.currentUser;
    if (user == null) {
      throw Exception("User not authenticated");
    }
    final token = await user.getIdToken(true);

    try {
      final response = await _dio.post<Map<String, dynamic>>(
        url,
        data: fileBytes,
        options: Options(
          headers: {
            "Content-Type": "image/jpeg",
            "Authorization": "Bearer $token",
          },
        ),
      );

      logger.i(response.data);
    } on DioException catch (e, stackTrace) {
      final terseStacktrace = Chain.forTrace(stackTrace).terse;

      logger
        ..e("Failed to upload profile picture", [e, terseStacktrace])
        ..e("Error ${e.error} Message ${e.message} Response ${e.response}");
    } catch (e, stackTrace) {
      final terseStacktrace = Chain.forTrace(stackTrace).terse;

      logger.wtf("Failed to upload profile picture", [e, terseStacktrace]);

      rethrow;
    }
  });
}

额外验证步骤

  1. 获取有效令牌后,用curl测试是否能正常上传:
curl -X POST --data-binary @/path/to/your/image.jpg \
-H "Authorization: Bearer YOUR_ACTUAL_TOKEN" \
-H "Content-Type: image/jpeg" \
"https://storage.googleapis.com/upload/storage/v1/b/YOUR_BUCKET_NAME/o?uploadType=media&name=test/profilePicture/test.jpg"

如果curl能成功,说明令牌有效,问题出在原Dio代码的实现上。

  1. 你的Storage规则已配置为允许所有读写操作,因此规则不是认证错误的原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:04:54