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内容解码错误"; } }
说明
- 清理非标准字符:用正则表达式精准移除所有不属于Base64标准的字符,比单纯移除空白更可靠。
- 自动补全padding:使用
padRight替代循环补全,代码更简洁高效。 - UTF-8解码:GitHub README通常使用UTF-8编码,解码字节后需用
utf8.decode()还原为字符串。
内容的提问来源于stack exchange,提问作者DData Science
相关产品推荐
相关产品推荐

