Rest 颤振可恢复上传到谷歌硬盘通过HTTP
基于上的文档,我正在尝试将一个文件上载到Google驱动器的根文件夹。我已经通过谷歌登录对用户进行了身份验证,这并不是一个问题。我一直收到服务器返回的411错误 “POST请求需要Rest 颤振可恢复上传到谷歌硬盘通过HTTP,rest,http,flutter,dart,google-drive-api,Rest,Http,Flutter,Dart,Google Drive Api,基于上的文档,我正在尝试将一个文件上载到Google驱动器的根文件夹。我已经通过谷歌登录对用户进行了身份验证,这并不是一个问题。我一直收到服务器返回的411错误 “POST请求需要内容长度标题。这就是我们所知道的。” 我有一个内容长度标题,但似乎不被接受。这是我的密码 Uri uri = Uri.parse('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable'); http.MultipartReques
内容长度标题。这就是我们所知道的。”
我有一个内容长度标题,但似乎不被接受。这是我的密码
Uri uri = Uri.parse('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable');
http.MultipartRequest request = new http.MultipartRequest('POST', uri);
request.headers["Authorization"] = header['Authorization'];
request.headers['content-type'] = "application/json; charset=UTF-8";
request.headers['X-Upload-Content-Type'] ='video/mp4';
request.headers['X-Upload-Content-Length'] = lengthInBytes.toString();
request.headers['name'] = fileName;
request.headers['content-length'] = (request.contentLength).toString();
//request.files.add(await http.MultipartFile.fromPath('$fileName', file.path,));
print("request.toString: " + request.toString());
http.StreamedResponse response = await request.send();
print('ok: ' + response.statusCode.toString());
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
我所知道的唯一一行是文件名,因为API站点上的文档略有不同,我不确定是否正确编码。下面是谷歌网站上的API示例
POST https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable HTTP/1.1
Authorization: Bearer [YOUR_AUTH_TOKEN]
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/jpeg
X-Upload-Content-Length: 2000000
{
"name": "myObject"
}
我可以为一个大约5MB大小的文件进行多部分上传,但我需要能够上传更大的文件,并且Resubable是唯一的选择。如果需要,我可以发布多部分代码。我使用http StreamedRequest类解决了这个问题。下面的代码与GoogleDriveV3一起上传mp4视频
Future handleUploadData(Map headers, String filename, String path) async {
final file = new File(path);
final fileLength = file.lengthSync().toString();
String sessionUri;
Uri uri = Uri.parse('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable');
String body = json.encode({ 'name' : filename });
final initialStreamedRequest =
new http.StreamedRequest('POST', uri)
..headers.addAll({
'Authorization': headers['Authorization'],
'Content-Length' : utf8.encode(body).length.toString(),
'Content-Type' : 'application/json; charset=UTF-8',
'X-Upload-Content-Type' : 'video/mp4',
'X-Upload-Content-Length' : fileLength
});
initialStreamedRequest.sink.add(utf8.encode(body));
initialStreamedRequest.sink.close();
http.StreamedResponse response = await initialStreamedRequest.send();
print("response: " + response.statusCode.toString());
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
if (response.statusCode == 200) {
sessionUri = response.headers['location'];
print(sessionUri);
}
Uri sessionURI = Uri.parse(sessionUri);
final fileStreamedRequest =
new http.StreamedRequest('PUT', sessionURI)
..headers.addAll({
'Content-Length' : fileLength,
'Content-Type' : 'video/mp4',
});
fileStreamedRequest.sink.add(file.readAsBytesSync());
fileStreamedRequest.sink.close();
http.StreamedResponse fileResponse = await fileStreamedRequest.send();
print("file response: " + fileResponse.statusCode.toString());
fileResponse.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
初始StreamRequest向GDrive发送一个请求,其中包含关于将要上载的文件的元数据,并接收一个位置URI,该位置URI在第二个文件StreamRequest中用于上载实际的文件数据。目前,这是在一个上传操作中完成的,但是它可以被分成块。我通过使用http StreamedRequest类解决了这个问题。下面的代码与GoogleDriveV3一起上传mp4视频
Future handleUploadData(Map headers, String filename, String path) async {
final file = new File(path);
final fileLength = file.lengthSync().toString();
String sessionUri;
Uri uri = Uri.parse('https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable');
String body = json.encode({ 'name' : filename });
final initialStreamedRequest =
new http.StreamedRequest('POST', uri)
..headers.addAll({
'Authorization': headers['Authorization'],
'Content-Length' : utf8.encode(body).length.toString(),
'Content-Type' : 'application/json; charset=UTF-8',
'X-Upload-Content-Type' : 'video/mp4',
'X-Upload-Content-Length' : fileLength
});
initialStreamedRequest.sink.add(utf8.encode(body));
initialStreamedRequest.sink.close();
http.StreamedResponse response = await initialStreamedRequest.send();
print("response: " + response.statusCode.toString());
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
if (response.statusCode == 200) {
sessionUri = response.headers['location'];
print(sessionUri);
}
Uri sessionURI = Uri.parse(sessionUri);
final fileStreamedRequest =
new http.StreamedRequest('PUT', sessionURI)
..headers.addAll({
'Content-Length' : fileLength,
'Content-Type' : 'video/mp4',
});
fileStreamedRequest.sink.add(file.readAsBytesSync());
fileStreamedRequest.sink.close();
http.StreamedResponse fileResponse = await fileStreamedRequest.send();
print("file response: " + fileResponse.statusCode.toString());
fileResponse.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
初始StreamRequest向GDrive发送一个请求,其中包含关于将要上载的文件的元数据,并接收一个位置URI,该位置URI在第二个文件StreamRequest中用于上载实际的文件数据。目前,这是在一个上传操作中完成的,但它可以分为多个块。我遇到了大致相同的问题,只是我试图上传一个文本文件,我想要一个单一的原子请求,以便能够使用文件etag的“If Match”头(当我写“update”时)代码,我正在进行同步,如果文件在同步过程中被其他地方更改,我不想覆盖该文件)
我真的很难使用http.post函数,即使我正确地设置了“Content-length”头,我还是遇到了“411-length-required”错误
Sean Coutinho使用http.StreamedRequest提供的解决方案为我提供了工作代码,我可以使用这些代码来实现我的请求,谢谢
我将在这里发布我的代码,以防它帮助其他人:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:google_sign_in/google_sign_in.dart';
enum RemoteFileType {
FOLDER,
FILE,
}
class RemoteFile {
final RemoteFileType fileType;
final String fileId;
final String fileName;
RemoteFile(
this.fileType,
this.fileId,
this.fileName,
);
}
// The boundary string
const String MULTIPART_REQUESTS_BOUNDARY_STRING = 'foo_bar_baz';
Map<String, String> _authHeaders;
String _createMultiPartRequestBodyString(
final Map<String, dynamic> requestMetaData,
final String fileContentString,
) {
return '\r\n--$MULTIPART_REQUESTS_BOUNDARY_STRING\r\n' +
'Content-Type: application/json; charset=UTF-8\r\n\r\n' +
jsonEncode(requestMetaData) +
'\r\n--$MULTIPART_REQUESTS_BOUNDARY_STRING\r\nContent-Type: text/plain\r\n\r\n' +
fileContentString +
'\r\n--$MULTIPART_REQUESTS_BOUNDARY_STRING--';
}
Future<RemoteFile> createNewTextFile(
final RemoteFile parentFolder,
final String fileName,
final String fileTextContent,
) async {
final Map<String, dynamic> requestMetaData = {
'mimeType': 'application/json',
'title': fileName,
'parents': [
{'id': parentFolder.fileId}
],
};
final String multiPartRequestBodyString = _createMultiPartRequestBodyString(requestMetaData, fileTextContent);
final http.StreamedRequest fileStreamedRequest = http.StreamedRequest(
'POST',
Uri.parse('https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart'),
);
fileStreamedRequest.headers.addAll({
'Authorization': _authHeaders['Authorization'],
'Accept': 'application/json',
'Content-Type': 'multipart/related; boundary=$MULTIPART_REQUESTS_BOUNDARY_STRING',
'Content-Length': multiPartRequestBodyString.length.toString(),
//'If-Match': 'my_etag_here_when_updating_existing_file_with_put',
});
fileStreamedRequest.sink.add(utf8.encode(multiPartRequestBodyString));
fileStreamedRequest.sink.close();
final http.StreamedResponse httpPostResponse = await fileStreamedRequest.send();
// Do what you want with the response too
//...
}
导入'dart:convert';
将“package:http/http.dart”导入为http;
导入“包:google_sign_in/google_sign_in.dart”;
枚举远程文件类型{
文件夹,
文件
}
类远程文件{
最终RemoteFileType文件类型;
最终字符串fileId;
最终字符串文件名;
远程文件(
此文件名为.fileType,
这个.fileId,
此文件名为.fileName,
);
}
//边界字符串
const String MULTIPART_REQUESTS_BOUNDARY_String='foo_bar_baz';
地图标题;
字符串\u createMultiPartRequestBodyString(
最终地图请求元数据,
最终字符串fileContentString,
) {
返回“\r\n--$MULTIPART\u请求\u边界\u字符串\r\n”+
'内容类型:application/json;charset=UTF-8\r\n\r\n'+
JSONECODE(请求元数据)+
“\r\n--$MULTIPART\u请求\u边界\u字符串\r\n内容类型:text/plain\r\n\r\n”+
fileContentString+
“\r\n--$MULTIPART\u请求\u边界\u字符串--”;
}
未来的createNewTextFile(
最终远程文件父文件夹,
最终字符串文件名,
最终字符串fileTextContent,
)异步的{
最终映射请求元数据={
'mimeType':'application/json',
“title”:文件名,
‘家长’:[
{'id':parentFolder.fileId}
],
};
最终字符串multiPartRequestBodyString=_createMultiPartRequestBodyString(requestMetaData,fileTextContent);
最终http.StreamedRequest fileStreamedRequest=http.StreamedRequest(
"岗位",,
parse('https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart'),
);
fileStreamedRequest.headers.addAll({
“授权”:_authHeaders[“授权”],
“接受”:“应用程序/json”,
“内容类型”:“多部分/相关;边界=$multipart\u请求\u边界\u字符串”,
“内容长度”:multiPartRequestBodyString.Length.toString(),
//'如果匹配':'当用'u put'更新现有的'u文件'u时,我的'u etag'在这里'u,
});
fileStreamedRequest.sink.add(utf8.encode(multiPartRequestBodyString));
fileStreamedRequest.sink.close();
final http.streamdresponse httpPostResponse=等待fileStreamedRequest.send();
//对回应也做你想做的事
//...
}
我遇到了大致相同的问题,只是我试图上传一个文本文件,我想要一个原子请求,以便能够将“If Match”头与文件etag一起使用(当我编写“update”代码时,我正在进行同步,如果在同步过程中文件被其他地方更改,我不想覆盖该文件)
我真的很难使用http.post函数,即使我正确地设置了“Content-length”头,我还是遇到了“411-length-required”错误
Sean Coutinho使用http.StreamedRequest提供的解决方案为我提供了工作代码,我可以使用这些代码来实现我的请求,谢谢
我将在这里发布我的代码,以防它帮助其他人:
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:google_sign_in/google_sign_in.dart';
enum RemoteFileType {
FOLDER,
FILE,
}
class RemoteFile {
final RemoteFileType fileType;
final String fileId;
final String fileName;
RemoteFile(
this.fileType,
this.fileId,
this.fileName,
);
}
// The boundary string
const String MULTIPART_REQUESTS_BOUNDARY_STRING = 'foo_bar_baz';
Map<String, String> _authHeaders;
String _createMultiPartRequestBodyString(
final Map<String, dynamic> requestMetaData,
final String fileContentString,
) {
return '\r\n--$MULTIPART_REQUESTS_BOUNDARY_STRING\r\n' +
'Content-Type: application/json; charset=UTF-8\r\n\r\n' +
jsonEncode(requestMetaData) +
'\r\n--$MULTIPART_REQUESTS_BOUNDARY_STRING\r\nContent-Type: text/plain\r\n\r\n' +
fileContentString +
'\r\n--$MULTIPART_REQUESTS_BOUNDARY_STRING--';
}
Future<RemoteFile> createNewTextFile(
final RemoteFile parentFolder,
final String fileName,
final String fileTextContent,
) async {
final Map<String, dynamic> requestMetaData = {
'mimeType': 'application/json',
'title': fileName,
'parents': [
{'id': parentFolder.fileId}
],
};
final String multiPartRequestBodyString = _createMultiPartRequestBodyString(requestMetaData, fileTextContent);
final http.StreamedRequest fileStreamedRequest = http.StreamedRequest(
'POST',
Uri.parse('https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart'),
);
fileStreamedRequest.headers.addAll({
'Authorization': _authHeaders['Authorization'],
'Accept': 'application/json',
'Content-Type': 'multipart/related; boundary=$MULTIPART_REQUESTS_BOUNDARY_STRING',
'Content-Length': multiPartRequestBodyString.length.toString(),
//'If-Match': 'my_etag_here_when_updating_existing_file_with_put',
});
fileStreamedRequest.sink.add(utf8.encode(multiPartRequestBodyString));
fileStreamedRequest.sink.close();
final http.StreamedResponse httpPostResponse = await fileStreamedRequest.send();
// Do what you want with the response too
//...
}
导入'dart:convert';
将“package:http/http.dart”导入为http;
导入“包:google_sign_in/google_sign_in.dart”;
枚举远程文件类型{
文件夹,
文件
}
类远程文件{
最终RemoteFileType文件类型;
最终字符串fileId;
最终字符串文件名;
远程文件(
此文件名为.fileType,
这个.fileId,
此文件名为.fileName,
);
}
//边界字符串
const String MULTIPART_REQUESTS_BOUNDARY_String='foo_bar_baz';
地图标题;
字符串\u createMultiPartRequestBodyString(
最终地图请求元数据,
最终字符串fileContentString,
) {
返回“\r\n--$MULTIPART\u请求\u边界\u字符串\r\n”+
'内容类型:application/json;charset=UTF-8\r\n\r\n'+
JSONECODE(请求元数据)+
'\r\n--$MULTIPART_