Flutter应用Google Drive可恢复上传:大文件无法获取会话URI
Flutter中Google Drive API断点续传POST请求大文件返回400错误
我在Flutter应用里基于Google Drive API实现了断点续传功能,用于上传大文件。流程需要先发送POST请求获取resumable session URI(响应的Location头),再用PUT请求上传文件内容。目前小文件(小于2MB)能正常获取会话URI,但大于2MB的文件POST请求直接返回400 Bad Request,多次测试问题依旧。
我的POST请求代码如下:
Uri uri = Uri.parse('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable'); var authToken = headers['Authorization']; String body = json.encode({ 'name' : fileName, 'originalFilename' : URN, 'parents' : [monthFolderId], 'contentHints' : [{ 'thumbnail' : { 'mimeType' : 'image/png', 'image' : base64Image } }] }); final initialStreamedRequest = new http.StreamedRequest('POST', uri) ..headers.addAll({ 'Authorization': authToken!, 'X-Upload-Content-Length' : zipFileLength.toString(), 'X-Upload-Content-Type' : 'application/octet-stream', 'Content-Length' : utf8.encode(body).length.toString(), 'Content-Type' : 'application/json; charset=UTF-8', }); initialStreamedRequest.sink.add(utf8.encode(body)); initialStreamedRequest.sink.close(); http.StreamedResponse response = await initialStreamedRequest.send() .onError((error, stackTrace) { return Future.error(error!); }); String? sessionUri; if (response.statusCode == 200) { sessionUri = response.headers['location']; }
问题排查与修复建议
修正contentHints格式错误
Google Drive API中contentHints是一个对象而非数组,你的代码里写成了数组[{...}],这会导致请求体JSON格式不符合API要求。小文件可能未触发严格校验,大文件则直接返回400。修改为:'contentHints': { 'thumbnail': { 'mimeType': 'image/png', 'image': base64Image } }移除手动设置的Content-Length头
StreamedRequest会自动处理请求体的Content-Length计算,手动设置可能因编码细节导致长度不匹配,引发400错误。直接删除'Content-Length' : utf8.encode(body).length.toString(),这一行。确保X-Upload-Content-Length准确
确认zipFileLength是文件的真实字节数,转字符串时没有格式错误(比如不要包含非数字字符)。查看400响应的详细错误信息
添加代码获取响应体内容,Google API会返回具体错误原因,帮助精准定位:if (response.statusCode != 200) { String errorBody = await response.stream.bytesToString(); print('Error details: $errorBody'); }确保请求体发送完整
关闭sink时加上await,确保所有数据都已发送:await initialStreamedRequest.sink.close();
修改后的完整代码示例
Uri uri = Uri.parse('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable'); var authToken = headers['Authorization']; String body = json.encode({ 'name': fileName, 'originalFilename': URN, 'parents': [monthFolderId], 'contentHints': { 'thumbnail': { 'mimeType': 'image/png', 'image': base64Image } } }); final initialStreamedRequest = http.StreamedRequest('POST', uri) ..headers.addAll({ 'Authorization': authToken!, 'X-Upload-Content-Length': zipFileLength.toString(), 'X-Upload-Content-Type': 'application/octet-stream', 'Content-Type': 'application/json; charset=UTF-8', }); initialStreamedRequest.sink.add(utf8.encode(body)); await initialStreamedRequest.sink.close(); http.StreamedResponse response = await initialStreamedRequest.send() .onError((error, stackTrace) => Future.error(error!)); // 打印错误详情 if (response.statusCode != 200) { String errorBody = await response.stream.bytesToString(); print('Error response: $errorBody'); } String? sessionUri; if (response.statusCode == 200) { sessionUri = response.headers['location']; }
内容的提问来源于stack exchange,提问作者Naveen N
相关产品推荐
相关产品推荐

