'How do I use StreamedRequest in Dart http library to upload a file?

I want to upload a file via a non-multipart/form-data request like this:

POST http://127.0.0.1/upload
Cache-Control: no-cache

< /path/to/file/in/disk

(I tested and it successfully uploaded a file from JetBrain Rider's REST client to my REST endpoint.)

There is a StreamedRequest class in http package but I didn't find any constructor or setter to plug a byte stream or file content into it.

How do I use StreamedRequest to upload a file in Dart?



Solution 1:[1]

I'm just going to post phqb's solution in case the pastebin link goes down:

final file = new File(filePath);

final streamedRequest =
    new http.StreamedRequest('POST', Configurations.getUserContentsApiUri('/upload'))
      ..headers.addAll({
        'Cache-Control': 'no-cache',
        'Authorization': 'Bearer $uploadToken',
      });
streamedRequest.contentLength = await file.length();
file.openRead().listen((chunk) {
  print(chunk.length);
  streamedRequest.sink.add(chunk);
}, onDone: () {
  streamedRequest.sink.close();
});

await streamedRequest.send();
print('after response');

Solution 2:[2]

Update:

A day after posting this I realized that this is not actually measuring the upload progress, but only the progress of reading the bytes from the local JSON payload, which is almost instantaneous. If/when I figure out how to actually measure the upload progress, I'll update this answer.


Original Answer:

This works for me:

import 'dart:convert';
import 'package:http/http.dart' as http;

// ...

final jsonPayload = {'base64File': 'abc123', 'something': 'else'};

// We are using a StreamedRequest so we can track the upload progress
final streamedRequest = http.StreamedRequest("POST", apiUri);
streamedRequest.headers['content-type'] = 'application/json';

// Length transferred (to calculate upload progress)
var transferredLength = 0;
// Upload progress (from 0.0 to 1.0)
var uploadProgress = 0.0;
// The stringified JSON payload
var stringEncodedPayload = jsonEncode(jsonPayload);
// Total length (to calculate upload progress)
var totalLength = stringEncodedPayload.length;

// Create a stream of the payload string
Stream.value(stringEncodedPayload)
  // Transform the string-stream to a byte stream (List<int>)
  .transform(utf8.encoder)
  // Start reading the stream in chunks, submitting them to the streamedRequest for upload
  .listen((chunk) {
    transferredLength += chunk.length;
    uploadProgress = transferredLength / totalLength;
    print("Chunk: ${chunk.length}, transferred: $transferredLength, progress: $uploadProgress");
    streamedRequest.sink.add(chunk);
  }, onDone: () {
    print("Done. Total: $totalLength, transferred: $transferredLength, progress: $uploadProgress");
    streamedRequest.sink.close();
  });

final result = await client.send(streamedRequest).then(http.Response.fromStream);


print("----------->");
print(result.statusCode);
print(result.body);
print("<-----------");

The output:

flutter: Chunk: 1024, transferred: 1024, progress: 0.0008807503580198599
flutter: Chunk: 1024, transferred: 2048, progress: 0.0017615007160397197
flutter: Chunk: 1024, transferred: 3072, progress: 0.0026422510740595796
...
flutter: Chunk: 1024, transferred: 1159168, progress: 0.9970094052784814
flutter: Chunk: 1024, transferred: 1160192, progress: 0.9978901556365013
flutter: Chunk: 1024, transferred: 1161216, progress: 0.9987709059945211
flutter: Chunk: 1024, transferred: 1162240, progress: 0.9996516563525409
flutter: Chunk: 405, transferred: 1162645, progress: 1.0
flutter: Done. Total: 1162645, transferred: 1162645, progress: 1.0

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mark
Solution 2