目录
- 前言
- 一、场景一:将图片/文件转为 Base64 字符串上传
- 为什么要 Base64?
- 完整代码模式
- 注意事项
- 二、场景二:解码 JWT Token 查看内容
- JWT 结构
- 解码 JWT Payload
- 三、场景三:对接要求 Base64 的第三方 API
- 典型请求格式
- 四、Demo 完整解码演示
- 五、辅助工具函数完整版
- 六、Base64 大小计算公式
- 七、总结
前言
近期发现一款很有意思的HarmonyOS 三方库, 地址 @pura/harmony-utils(V1.4.0) , 作者是"桃花镇童长老", 我这里也是直接通过该作者公布的源码进行案例编写进行,写了到目前写了一部分demo ,感觉确实很有帮助,这里呢也是开始写一个系列的演示demo 供大家参考。如有帮助可以在OpenHarmony中进行下载安装进行使用哦
案例demo导航展示
↓↓↓↓↓↓接下来言归正传 ↓↓↓↓
光懂 API 不够,得知道什么时候用。
这篇文章列举几个 Base64 在实际开发中最常见的场景,结合Base64DemoPage.ets的完整演示代码,帮你理解"在什么地方、为什么、怎么用"。
一、场景一:将图片/文件转为 Base64 字符串上传
为什么要 Base64?
HTTP 的 JSON 格式只能传文本,无法直接传二进制。当 API 服务端要求把图片放在 JSON 字段里时,就需要先把图片二进制转成 Base64 字符串。
完整代码模式
// 假设从文件系统读取了图片字节数组asyncfunctionuploadImageAsBase64(imageBytes:Uint8Array){// 编码为 Base64 字符串constbase64Str=awaitBase64Util.encodeToStr(imageBytes);// 放进 JSON 发送constbody=JSON.stringify({image:base64Str,filename:'photo.jpg',mimeType:'image/jpeg'});// 发起请求(示意)console.log('上传数据:',body.substring(0,50)+'...');console.log('Base64 长度:',base64Str.length,'字符');// Base64 编码后体积约为原始的 4/3 倍}注意事项
Base64 编码后文件体积会增加约33%(原始 3 字节变成 4 个字符)。对于大文件(超过 1MB),建议改用 multipart/form-data 上传,不要用 Base64。
二、场景二:解码 JWT Token 查看内容
JWT 结构
JWT(JSON Web Token)由三部分组成,用.分隔:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ← Header(Base64 URL编码) .eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikhhcm1vbnlPUyIsImlhdCI6MTUxNjIzOTAyMn0 ← Payload .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ← SignatureHeader 和 Payload 是 Base64 URL 编码(-替代+,_替代/),可以直接解码看内容。
解码 JWT Payload
functiondecodeJwtPayload(jwt:string):object|null{try{constparts=jwt.split('.');if(parts.length!==3)returnnull;// JWT 用 URL_SAFE Base64,但可能没有补 = 号,需要手动补齐letbase64=parts[1];// 补 = 号(Base64 长度必须是 4 的倍数)while(base64.length%4!==0){base64+='=';}constdecodedBytes=Base64Util.decodeSync(base64);constjsonStr=uint8ArrayToText(decodedBytes);returnJSON.parse(jsonStr);}catch(e){console.error('JWT 解码失败:',(easError).message);returnnull;}}三、场景三:对接要求 Base64 的第三方 API
某些第三方服务(OCR、语音识别、图像分析)的 HTTP API 会要求把文件以 Base64 格式放在请求体里。
典型请求格式
interfaceOcrRequest{image:string;// Base64 编码的图片imageType:string;// 'BASE64'}asyncfunctioncallOcrApi(imageBytes:Uint8Array):Promise<string>{constbase64Image=awaitBase64Util.encodeToStr(imageBytes);constrequestBody:OcrRequest={image:base64Image,imageType:'BASE64'};// 调用 OCR API...return'识别结果';}四、Demo 完整解码演示
Base64DemoPage.ets的解码 Tab 演示了如何把一段 Base64 字符串解码回原文:
asyncrunDecode(){if(this.inputText.trim()===''){this.addLog('解码','请输入 Base64 字符串','warn');return;}try{letdecoded:Uint8Array;if(this.syncMode){decoded=Base64Util.decodeSync(this.inputText.trim());}else{decoded=awaitBase64Util.decode(this.inputText.trim());}consttext=this.uint8ArrayToText(decoded);this.results=[{label:'解码结果',value:text,byteLen:decoded.length},];this.addLog('解码',`解码成功${decoded.length}字节`,'success');}catch(e){this.addLog('解码',`解码失败:${(easError).message}`,'error');}}配套 UI(解码 Tab):
// 解码演示 Tab 内容Column(){Text('Base64 字符串').fontSize(13).fontColor('#666').fontWeight(FontWeight.Medium).alignSelf(ItemAlign.Start).margin({bottom:6})TextArea({text:this.inputText,placeholder:'粘贴 Base64 字符串...'}).width('100%').height(80).fontSize(12).backgroundColor('#F5F6FA').borderRadius(8).onChange((val:string)=>{this.inputText=val;})Row(){Radio({value:'syncDecode',group:'decodeMode'}).checked(this.syncMode).onChange((v:boolean)=>{if(v){this.syncMode=true;}})Text('同步 decodeSync').fontSize(12).margin({left:4})Blank()Radio({value:'asyncDecode',group:'decodeMode'}).checked(!this.syncMode).onChange((v:boolean)=>{if(v){this.syncMode=false;}})Text('异步 decode').fontSize(12).margin({left:4})}.margin({top:10})Button('解码').width('100%').height(44).borderRadius(10).backgroundColor('#00C853').fontColor('#FFF').fontSize(14).margin({top:12}).onClick(()=>{this.runDecode();})}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(12)ForEach(this.results,(res:EncodeResult)=>{Column(){Text('解码结果').fontSize(12).fontColor('#888').margin({bottom:4})Text(res.value).fontSize(13).width('100%').copyOption(CopyOptions.LocalDevice)}.width('100%').padding(14).backgroundColor('#E8F5E9').borderRadius(12).border({width:1,color:'#A5D6A7'}).margin({top:12})},(res:EncodeResult)=>res.label)五、辅助工具函数完整版
在Base64DemoPage.ets中,两个辅助函数处理字符串和字节数组的互转:
textToUint8Array(text:string):Uint8Array{constarr:number[]=[];for(leti=0;i<text.length;i++){arr.push(text.charCodeAt(i));}returnnewUint8Array(arr);}uint8ArrayToText(arr:Uint8Array):string{letresult='';for(leti=0;i<arr.length;i++){result+=String.fromCharCode(arr[i]);}returnresult;}copyToClipboard(text:string){try{AppStorage.setOrCreate('clipboard_temp',text);ToastUtil.showShort('已复制到临时存储');this.addLog('复制','结果已复制','info');}catch(e){this.addLog('复制','复制失败','error');}}六、Base64 大小计算公式
编码后字节数 = Math.ceil(原始字节数 / 3) × 4| 原始大小 | Base64 大小 | 增大比例 |
|---|---|---|
| 100 B | 136 B | +36% |
| 1 KB | 1.37 KB | +37% |
| 100 KB | 137 KB | +37% |
| 1 MB | 1.37 MB | +37% |
这就是为什么大文件不建议用 Base64——光是这 37% 的额外体积就很可观了。
七、总结
Base64Util 的实战场景主要三类:
- 上传二进制到 JSON API:
encodeToStr(imageBytes)转字符串 - 解析服务端 Base64 数据:
decodeSync(base64Str)转回字节 - 与第三方 API 对接:按对方要求选合适的编码变体(标准/URL安全)
记住:Base64 = 编码,不是加密。要保护数据还需要加密(比如 AES)。