如何用Google Drive JavaScript API更新Zip文件及修复损坏问题
我之前也碰到过类似的二进制文件上传异常的问题,结合你的代码和现象来看,核心问题出在二进制数据被错误当成文本处理上,下面给你拆解问题和解决方案:
问题背景
你在项目中用zip.js生成Zip文件,本地下载后能正常解压,但通过Google Drive API更新文件时,明明没添加额外数据,却出现体积翻倍、文件损坏的情况。从你提供的原始Zip内容和FileReader读取后的内容对比来看,原始的二进制字节已经被破坏(比如PKÊL变成了PK�U�L),这就是问题的根源。
问题分析
你原来的代码里用了FileReader.readAsText()来读取Zip Blob的内容:
reader.readAsText(zippedBlob)
Zip是纯二进制格式,而readAsText()会默认按照UTF-8编码去解析二进制数据,这会把无法被UTF-8识别的字节转换成乱码字符,破坏了原始的二进制结构。把这些被损坏的文本内容上传到Google Drive后,自然会导致文件体积异常、无法正常解压。
解决方案
要解决这个问题,我们需要用base64编码来传输二进制数据,避免文本编码对二进制内容的破坏,具体步骤如下:
1. 正确读取Zip Blob为base64格式
把readAsText()改成readAsDataURL(),然后去掉data URL的前缀,获取纯净的base64编码数据:
// 替换原来的FileReader读取逻辑 var reader = new FileReader(); reader.addEventListener("loadend", function() { // 去掉data:application/zip;base64,前缀,得到纯base64内容 const base64Data = reader.result.replace("data:application/zip;base64,", ""); callback(base64Data); }); reader.readAsDataURL(zippedBlob);
2. 修改Google Drive API的上传请求
在multipart请求体中,为Zip数据部分添加Content-Transfer-Encoding: base64头,明确告诉Google Drive这是base64编码的二进制数据:
// 替换原来的multipartRequestBody构造代码 var multipartRequestBody = delimiter + 'Content-Type: application/json\r\n\r\n' + '{}' + // 这里可以填写文件元数据,比如{"name": "新文件名.zip"},不需要就留空对象 delimiter + 'Content-Type:' + mimeType + '\r\n' + 'Content-Transfer-Encoding: base64\r\n\r\n' + base64Data + close_delim;
修改后的完整核心代码
生成Zip并获取base64的函数
function createZip(data, fileName, callback) { var blob = new Blob([data], { type: "text/xml" }); zipBlob(fileName, blob, function(zippedBlob) { var reader = new FileReader(); reader.addEventListener("loadend", function() { const base64Data = reader.result.replace("data:application/zip;base64,", ""); callback(base64Data); }); reader.readAsDataURL(zippedBlob); }); function zipBlob(filename, blob, callback) { zip.createWriter(new zip.BlobWriter("application/zip"), function(zipWriter) { zipWriter.add(filename, new zip.BlobReader(blob), function() { zipWriter.close(callback); }); }, function(error) { console.error(error); }); } }
更新Google Drive文件的函数
this.updateFile = function(id, base64Data, accessToken, callback) { var boundary = '-------314159265358979323846', delimiter = "\r\n--" + boundary + "\r\n", close_delim = "\r\n--" + boundary + "--", mimeType = 'application/zip'; var multipartRequestBody = delimiter + 'Content-Type: application/json\r\n\r\n' + '{}' + // 可根据需求修改文件元数据 delimiter + 'Content-Type:' + mimeType + '\r\n' + 'Content-Transfer-Encoding: base64\r\n\r\n' + base64Data + close_delim; gapi.client.request({ 'path': '/upload/drive/v3/files/'+id, 'method': 'PATCH', 'params': { 'uploadType': 'multipart' }, 'headers': { 'Content-Type': 'multipart/mixed; boundary="' + boundary + '"', 'Authorization': 'Bearer ' + accessToken, }, 'body': multipartRequestBody }).execute(function(file) { if (typeof callback === "function") callback(file); }, function(error) { console.error(error); callback(error); }); }
这样修改后,二进制的Zip内容会以base64的方式正确传输,Google Drive会自动解码并保存原始的Zip文件,不会再出现体积翻倍和损坏的问题了。
内容的提问来源于stack exchange,提问作者phuwin

