Rest 颤振可恢复上传到谷歌硬盘通过HTTP

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

基于上的文档,我正在尝试将一个文件上载到Google驱动器的根文件夹。我已经通过谷歌登录对用户进行了身份验证,这并不是一个问题。我一直收到服务器返回的411错误

“POST请求需要
内容长度
标题。这就是我们所知道的。”

我有一个内容长度标题,但似乎不被接受。这是我的密码

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_