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

Flutter/Dart中GitHub API返回的Base64内容解码失败问题

解决Dart/Flutter中GitHub API返回的Base64编码README解码失败问题

问题概述

通过GitHub API获取仓库README文件时,接口返回的内容以Base64编码格式呈现,但在Flutter/Dart中调用base64.decode()解码时,触发了FormatException: Invalid character错误。

错误信息

Unhandled exception:
FormatException: Invalid character (at character 61)
PGRpdiBhbGlnbj0iY2VudGVyIj4KCiMgTmFtYXN0ZSDwn5mPLCBJJ20gRGVl
                                                            ^

#0      _Base64Decoder.decodeChunk (dart:convert/base64.dart:705:7)
#1      _Base64Decoder.decode (dart:convert/base64.dart:629:14)
#2      Base64Decoder.convert (dart:convert/base64.dart:509:26)
#3      Base64Codec.decode (dart:convert/base64.dart:83:47)
#4      main (file:///home/deepesh/Development/public/learn/flutter-dart/git_search_flutter/learn.dart:6:24)
#5      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#6      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)

测试代码

import 'dart:convert';

const content =
    "PGRpdiBhbGlnbj0iY2VudGVyIj4KCiMgTmFtYXN0ZSDwn5mPLCBJJ20gRGVl\ncGVzaCBLYWx1cmEg8J+RqOKAjfCfkrsKCiFbTWFpbiBJbWFnZV0oLi9hc3Nl\ndHMvZ2l0aHViRGVzaWduVjElMjAoMSkucG5nKQoKPHAgYWxpZ249ImxlZnQi\nPgogICAgSSBhbSBhIHNvZnR3YXJlIGVuZ2luZWVyIHdobyBiZWxpZXZlcyBp\nbiBidWlsZGluZyBhbmQgbWFpbnRhaW5pbmcgcHJvamVjdHMuIEkgYWx3YXlz\nIGhvcGUgZm9yIHRoZSBiZXN0IGJ1dCBwcmVwYXJlIGZvciB0aGUgd29yc3Qu\nIFlvdSBjYW4gY291bnQgb24gbWUgdG8gdHVybiB2aXNpb24gaW50byByZWFs\naXR5Lgo8L3A+Cgo8cCBhbGlnbj0ibGVmdCI+CiAgPHN0cm9uZz5JIG1ha2Ug\nc3VyZSB0byBhdm9pZCB0aGUgeCB5IHByb2JsZW0uPHN0cm9uZz4KPHA+Cgoj\nIyBHaXRodWIgU3RhdHVzCgo8dGFibGUgYm9yZGVyPSIwIj4KICA8dHI+CiAg\nICA8dGg+CiAgICAgICAgPGltZyBzcmM9Imh0dHBzOi8vZ2l0aHViLXJlYWRt\nZS1zdHJlYWstc3RhdHMuaGVyb2t1YXBwLmNvbT91c2VyPURlZXBlc2hLYWx1\ncmEmdGhlbWU9c2hhZG93LWJsdWUmYm9yZGVyX3JhZGl1cz0xMCI+CiAgICA8\nL3RoPgogICAgPHRoPgogICAgICAgIDxpbWcgc3JjPSJodHRwczovL2dpdGh1\nYi1yZWFkbWUtc3RhdHMudmVyY2VsLmFwcC9hcGk/dXNlcm5hbWU9RGVlcGVz\naEthbHVyYSZzaG93X2ljb25zPXRydWUmdGhlbWU9c2hhZG93X2JsdWUiPgog\nICAgPC90aD4KICA8L3RyPgo8L3RhYmxlPgoKIyMgUHJvamVjdHMKCjxhIGhy\nZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9EZWVwZXNoS2FsdXJhL0hlYWxpeFNl\ncnZlciI+CiAgPGltZyBzcmM9Imh0dHBzOi8vZ2l0aHViLXJlYWRtZS1zdGF0\ncy52ZXJjZWwuYXBwL2FwaS9waW4/dXNlcm5hbWU9RGVlcGVzaEthbHVyYSZy\nZXBvPUhlYWxpeFNlcnZlciZ0aGVtZT1zaGFkb3dfYmx1ZSIgLz4KPC9hPgo8\nYSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vRGVlcGVzaEthbHVyYS8yX3Nv\nY2lhbF9tZWRpYV9weXRob25fZmFzdF9BcGkiPgogIDxpbWcgc3JjPSJodHRw\nczovL2dpdGh1Yi1yZWFkbWUtc3RhdHMudmVyY2VsLmFwcC9hcGkvcGluLz91\nc2VybmFtZT1EZWVwZXNoS2FsdXJhJnJlcG89Ml9zb2NpYWxfbWVkaWFfcHl0\naG9uX2Zhc3RfQXBpJnRoZW1lPXNoYWRvd19ibHVlIiAvPgo8L2E+CjxhIGhy\nZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9EZWVwZXNoS2FsdXJhL2ZpdGJ1ZGR5\nX25vcnRoX3Nob3JlX2hhY2siPgogIDxpbWcgc3JjPSJodHRwczovL2dpdGh1\nYi1yZWFkbWUtc3RhdHMudmVyY2VsLmFwcC9hcGkvcGluP3VzZXJuYW1lPURl\nZXBlc2hLYWx1cmEmcmVwbz1maXRidWRkeV9ub3J0aF9zaG9yZV9oYWNrJnRo\nZW1lPXNoYWRvd19ibHVlIiAvPgo8L2E+CgoKIyMgQ29ubmVjdCBIZXJlCjxh\nIGhyZWY9Imh0dHBzOi8vdHdpdHRlci5jb20vRGVlcGVzaEthbHVyYTEiPgog\nIDxpbWcgYWxpZ249ImxlZnQiIGFsdD0iRGVlcGVzaCBLYWx1cmEgfCBUd2l0\ndGVyIiB3aWR0aD0iMjFweCIgc3JjPSJodHRwczovL3Jhdy5naXRodWJ1c2Vy\nY29udGVudC5jb20vRGVlcGVzaEthbHVyYS9EZWVwZXNoS2FsdXJhL21haW4v\nYXNzZXRzL2ljb25zL3R3aXR0ZXItc3ZncmVwby1jb20uc3ZnIiAvPgo8L2E+\nCgoKCjwvZGl2Pg==\n";

void main() {
  var decoder = base64.decode(content);
  print(decoder);
}

当前临时处理方案

通过移除空白字符、补全Base64 padding并添加异常处理来规避错误:

import 'dart:convert';
late String markdown;

Future<String> markdownFunction() async {
  var profileMarkdown = await profileRenderKernaHai();
  var bodyMarkdown = profileMarkdown?.content;

  if (bodyMarkdown == null) {
    return "No Markdown";
  } else {
    // 打印Base64字符串用于调试
    print('Base64 String: $bodyMarkdown');

    // 移除所有多余空白字符
    bodyMarkdown = bodyMarkdown.replaceAll(RegExp(r'\s+'), '');

    // 确保Base64长度是4的倍数,补全padding
    while (bodyMarkdown!.length % 4 != 0) {
      bodyMarkdown += '=';
    }

    try {
      var decoded = base64.decode(bodyMarkdown);
      return utf8.decode(decoded);
    } catch (e) {
      // 处理或打印错误
      print('Error decoding base64 string: $e');
      return "Error: Invalid Markdown";
    }
  }
}

正确解决方案

问题根源

GitHub API返回的Base64内容包含换行符(\n),这些是为了可读性添加的格式字符,但标准Base64编码只允许A-Z、a-z、0-9、+、/、=这些字符,Dart的base64.decode()默认使用严格模式,遇到非标准字符就会抛出异常。

优化后的解码代码

import 'dart:convert';

Future<String> decodeGitHubReadme(String? base64Content) async {
  if (base64Content == null) {
    return "无Markdown内容";
  }

  // 移除所有非Base64标准字符(换行、空格等)
  final cleanedContent = base64Content.replaceAll(RegExp(r'[^A-Za-z0-9+/=]'), '');

  // 自动补全Base64 padding,确保长度是4的倍数
  final paddedContent = cleanedContent.padRight(
    cleanedContent.length + (4 - cleanedContent.length % 4) % 4,
    '=',
  );

  try {
    final decodedBytes = base64.decode(paddedContent);
    return utf8.decode(decodedBytes);
  } catch (e) {
    print('解码失败: $e');
    return "Markdown内容解码错误";
  }
}

说明

  1. 清理非标准字符:用正则表达式精准移除所有不属于Base64标准的字符,比单纯移除空白更可靠。
  2. 自动补全padding:使用padRight替代循环补全,代码更简洁高效。
  3. UTF-8解码:GitHub README通常使用UTF-8编码,解码字节后需用utf8.decode()还原为字符串。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:37:04