Возобновляемая загрузка Flutter на Google Drive через HTTP - PullRequest
0 голосов
/ 27 февраля 2020

На основании документации по Google Drive API Я пытаюсь загрузить файл в папку root на Google Диске. У меня есть аутентификация пользователя через Google Sign In, и это не было проблемой. Я получаю сообщение об ошибке 411, возвращаемое сервером:

«Для запросов POST требуется заголовок Content-length. Это все, что мы знаем».

У меня есть Заголовок длины содержимого, но, похоже, он не принят. Вот код, который у меня есть,

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);
});

Единственная знакомая мне строка выглядит как fileName, так как документация на сайте API немного отличается, и я не уверен, что кодирую это правильно. Вот пример API на сайте Google:

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"
}

Я могу сделать многокомпонентную загрузку для файла размером около 5 МБ, но мне нужно иметь возможность загружать более крупные файлы, и единственная возможность - возобновление. Я могу опубликовать код, состоящий из нескольких частей, который работает при необходимости.

1 Ответ

1 голос
/ 28 февраля 2020

Я решил проблему с помощью класса http StreamedRequest. Приведенный ниже код работает с Google Drive V3 для загрузки видео в формате 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 местоположения, который является используется во втором файле StreamRequest для загрузки актуальных данных файла. В настоящее время это выполняется одним действием загрузки, но его можно разбить на куски.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...