I am currently trying to process an image on the server that was uploaded by a user. My goal is to take this image that was uploaded, process it on the server and then upload it to rackspace cloud files. I have had no luck in finding a way. I am hoping that someone can lead me into the correct direction.
Heres what I have so far on the server side for processing
Future < Null > handleUploadRequest(final HttpRequest httpRequest) async {
print('handle upload -------------------------');
var data;
await httpRequest.fold(new BytesBuilder(), (b, d) => b..add(d)).then((builder) {
data = builder.takeBytes();
String encodedData = JSON.encode(data);
int dataLength = encodedData.length;
// Uploading image to rackspace cloud files
// Here we have to send a request with username & api key to get an auth token
http.post(tokens, headers : {'Content-Type':'application/json'}, body: JSON.encode({"auth": {"RAX-KSKEY:apiKeyCredentials":{"username":"XXXXXXXXXXXXXXX","apiKey":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}}})).then((response) {
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
return response;
}).then((response){
authResponse = JSON.decode(response.body);
String token = authResponse['access']['token']['id'];
/////////// This is where we upload the image to Rackspace ///////
var request = new http.MultipartRequest("PUT", Uri.parse('https://storage101.iad3.clouddrive.com/v1/MossoCloudFS_XXXXXXX/TestContainer/testimage.jpg'));
request.headers['X-Auth-Token'] = token;
request.headers['Content-Type'] = 'image/jpeg';
var stream = new http.ByteStream.fromBytes(data);
request.files.add(new http.MultipartFile('file', stream, data.length, filename: 'testfile.jpg', contentType: 'image/jpeg');
print('requesT: ${request}');
request.send().then((response) {
print(response.statusCode);
print(response.headers);
print(response.stream);
if (response.statusCode == 200) print("Uploaded!");
});
//// End of Upload to Rackspace //////////
print('Upload Complete!');
httpRequest.response.write(data);
await httpRequest.response.close();
}
The only issue right now is that in https://pub.dartlang.org/packages/http, I need to call the type MediaType in the parameter content-type. I have no idea how to call this. It seems like it is a factory inside a class? If I do not call a content-type then it defaults to octet-stream which cannot be opened from the cdn storage container.
Reference to this way of uploading is from How can I upload a PDF using Dart's HttpClient?
Looks like an missing return before http.put(...) and httpRequest.response.close();
Either you use await before each async call (call to functions which return a Future) or return each such Future to the caller to preserve order of execution. Without any of these the async execution is scheduled for later execution and the next line of your code is executed instead before the async code you called even started.
Update pure async/await implementation
import 'package:http/http.dart' as http;
import 'dart:async' show Future, Stream;
import 'dart:io';
Future<Null> handleUploadRequest(final HttpRequest httpRequest) async {
print('handle upload -------------------------');
print('httpRequest: ${httpRequest.headers}');
var data;
var builder = await httpRequest.fold(new BytesBuilder(), (b, d) => b..add(d));
data = builder.takeBytes();
print('bytes builder: ${data}');
// Uploading image to rackspace cloud files
var url =
'https://storage101.dfw1.clouddrive.com/v1/{accountnumber}/{container}/';
var response = await http.put(url,
headers: {
'X-Auth-Token': '{XXXXXXXXXAPI_KEYXXXXXXXXXX}',
'Content-Type': 'image/jpeg',
'Content-Length': '${httpRequest.headers.contentLength}',
},
body: data);
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
print('closing connection with data complete');
httpRequest.response.write(data);
await httpRequest.response.close();
}
Related
Context: I need to send media templates in which I need to send local files. Thus I need to upload the files to the WhatsApp API to get the Media Id, which I can then use to send the message templates.
The issue: I am running into errors while sending the post request to the server through DART. However the same call is working when sent through postman. I have tried sending the data both as a JSON and as form-data, but both are returning errors. I am attaching the code below, as well as the errors I am facing. Any help is really appreciated.
Getting the file path
upload() async{
if(await Permission.storage.isGranted){
FilePickerResult? choice = await FilePicker.platform.pickFiles(allowMultiple: false);
String? path = choice?.files.single.path;
if(path != null){
uploadJson(path);
// uploadFormData(path);
}
}else{
Permission.storage.request();
}
}
Uploading JSON
uploadJson(String path) async{
File imgfile = File(path);
Uint8List imgbytes = await imgfile.readAsBytes();
String bs4str = base64.encode(imgbytes);
print(bs4str);
var headers = {
'Authorization': variables.authorizationToken,
"Content-Type": 'application/json',
};
var body = jsonEncode({
'file': '$bs4str;type=image/jpeg',
'messaging_product':'whatsapp'
});
Response response = await post(Uri.parse('${variables.baseURL}${variables.phoneNumberId}/media'), headers: headers, body: body);
print(response.body);
}
Uploading as Form-data
uploadFormData(String path) async {
var headers = {
'Authorization': 'Bearer EAAGtvNhUHUIBANf5KvyxnZCUKcRn3jTJgPZBR2AbbVhZBZBO7GjoDCnS26FQT6Nr6qdRV993ZCJEbGwiqZCdQ7TZBJX8S6KXQdOTgmSf9ue7GCEN1IL3yqfAUEIN1bw0nyvptHeZBFCsdfwpxZAcS1ZCbCdmqArZC81orVbYRkzJy1h7ChOAygmrchfFtJAapykZAadruFqOWwcVvtudMezse94zENBNVZA0k7pAZD',
};
var request = MultipartRequest('POST', Uri.parse('https://graph.facebook.com/v14.0/106822672107550/media'));
request.fields.addAll({
'messaging_product': 'whatsapp'
});
request.files.add(await MultipartFile.fromPath('file', path));
request.headers.addAll(headers);
Response response = await Response.fromStream(await request.send());
print(response.body);
}
Error for JSON:
flutter: {"error":{"message":"An unknown error has occurred.","type":"OAuthException","code":1,"fbtrace_id":"AE72st2KT8wJFQ_wYvrcJY6"}}
Error for Form-Data:
flutter: {"error":{"message":"(#100) Param file must be a file with one of the following types: audio\/aac, audio\/mp4, audio\/mpeg, audio\/amr, audio\/ogg, audio\/opus, application\/vnd.ms-powerpoint, application\/msword, application\/vnd.openxmlformats-officedocument.wordprocessingml.document, application\/vnd.openxmlformats-officedocument.presentationml.presentation, application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application\/pdf, text\/plain, application\/vnd.ms-excel, image\/jpeg, image\/png, image\/webp, video\/mp4, video\/3gpp. Received file of type 'application\/octet-stream'.","type":"OAuthException","code":100,"fbtrace_id":"AfsxKl38CW7hUF_ixMzNha9"}}
The problem was with the Mime-type of the file. The Multi-Part file class needed the mime-type of the file to be declared while uploading the file, or the file was automatically being uploaded as an octlet-stream. The code to the working request is posted below.
var request = http.MultipartRequest('POST', Uri.parse('https://graph.facebook.com/v14.0/${variables.phoneNumberId}/media'));
request.headers.addAll({
'Authorization': variables.authorizationToken,
'Content-Type': 'multipart/form-data'
});
request.fields.addAll({
'messaging_product': 'whatsapp',
'type': 'application/pdf'
});
// The MIME type of the image or file
const mimeType = 'application/pdf';
// Open the image file
var file = File(path);
// Create a MultipartFile from the File object
final multipartFile = await http.MultipartFile.fromPath(
'file',
file.path,
contentType: MediaType.parse(mimeType),
);
// Create a request body containing the multipart file
request.files.add(multipartFile);
// Send the request
final response = await request.send();
// Check the response status code
if (response.statusCode == 200) {
String body = await response.stream.bytesToString();
var json = jsonDecode(body);
print(json['id']);
} else {
print(response.reasonPhrase);
}
I've been searching in vain for a simple way of uploading a JSON file to a specific URL but I haven't been able to find one, for Flutter.
I have implemented the code to download a simple JSON file from a specific URL. What I haven't been able to find is how to upload the same file to same location.
Do I need to do the multipart stuff? And I'm not even sure how that works.
EDIT
I'm starting with Map data (Map) and I want to upload it to a server as JSON (text file). This code is specific to binary data. And yes, I'm just writing to a URL, not an endpoint:
Upload(File imageFile) async {
var stream = new
http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var uri = Uri.parse(uploadURL);
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
//contentType: new MediaType('image', 'png'));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
To upload files to an endpoint, you can use http.MultipartRequest - this allows you to upload files with binary content (images, docs, etc.) and files with regular text.
import 'package:http/http.dart' as http;
String url = // your endpoint
var req = http.MultipartRequest('POST', Uri.parse(url));
Then to upload
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(
await http.MultipartFile.fromPath(
'json',
filePath
)
);
var res = await request.send();
I need a reusable function that makes an HTTP request and awaits for its completion before returning the response as a String.
Here's the main function:
main() async {
var json;
json = await makeRequest('https://...');
print(json);
print('*** request complete ***');
}
(First Case) This is the reusable function that makes the HTTP request:
makeRequest(String url) async {
var request = await new HttpClient().postUrl(Uri.parse(url));
// Includes the access token in the request headers.
request.headers.add(...);
// Waits until the request is complete.
var response = await request.close();
await for (var contents in response.transform(UTF8.decoder)) {
return contents;
}
}
This works as expected and the output is:
// Response contents as a String...
*** request complete ***
(Second Case) Then I tried to do this and it didn't work:
makeRequest(String url) async {
var request = await new HttpClient().postUrl(Uri.parse(url));
// Includes the access token in the request headers.
request.headers.add(...);
// Waits until the request is complete.
var response = await request.close();
var json = '';
await response.transform(UTF8.decoder).listen((contents) {
// At first I tried to return contents here, but then I added onDone().
json += contents;
}, onDone: () {
return json;
});
return json;
}
I've tried defining the function within listen with async and await, returning contents within listen without onDone(), but the output is the same:
// Empty line.
*** request complete ***
// Waits a few seconds doing nothing before terminating...
Does anyone know why the second case doesn't work?
EDIT:
After updating the code it does what it was supposed to do, but takes a few seconds before terminating execution:
Future<String> twitterRequest(String url) async {
var request = await new HttpClient().postUrl(Uri.parse(url));
// Includes the access token in the request headers.
request.headers.add(...);
// Waits until the request is complete.
var response = await request.close();
var json = '';
await for (var contents in response.transform(UTF8.decoder)) {
json += contents;
// Putting a break here produces the same output but terminates immediately (as wanted).
}
return json;
}
Output:
// Prints response contents...
*** request complete ***
// Takes a few seconds before execution terminates. With the break the code terminates immediately.
EDIT2:
After submitting this issue on GitHub, I found out that instances of the HttpClient have a connection pool and keep persistent connections by default, which keeps the Dart VM alive. Please consult the issue page to find out about the possible solutions.
It's probably caused by the await before the response.transform.
You might want something like
return response.transform(UTF8.decoder).join('');
The pause is not related to makeRequest(). The Dart VM seems to wait for something before it exits. Adding exit(0); as last line in main() makes the application exit immediately.
Update
According to the response on the Dart SDK issue
This is caused by the HttpClient instance having a connection pool
which can keep the Dart VM alive. There are two ways of avoiding this:
1) Close the HttpClient explicitly
2) Use non-persistent connections
import 'dart:async';
import 'dart:convert' show UTF8;
import 'dart:io';
Future main() async {
await makeRequest();
print('end of main');
}
Future makeRequest() async {
var client = new HttpClient();
var request = await client.postUrl(Uri.parse('https://example.com'));
var response = await request.close();
var contents = await response.transform(UTF8.decoder).join();
print(contents);
client.close(); // Close the client.
}
import 'dart:async';
import 'dart:convert' show UTF8;
import 'dart:io';
Future main() async {
await makeRequest();
print('end of main');
}
Future makeRequest() async {
var request = await new HttpClient().postUrl(Uri.parse('https://example.com'));
request.persistentConnection = false; // Use non-persistent connection.
var response = await request.close();
var contents = await response.transform(UTF8.decoder).join();
print(contents);
}
I am trying to process images uploaded from client on the server but am receiving the following errors. Am I processing the httpRequest wrong?
Unhandled exception:
Uncaught Error: HttpException: Connection closed while receiving data, uri = /api/upload
/// Client Code (dart file) (Works # sending request)
sendData(dynamic data) {
final req = new HttpRequest();
FormData fd = new FormData();
fd.append('uploadContent', data);
fd.appendBlob('uploadContent', data);
req.open("POST", "http://127.0.0.1:8080/api/upload", async: true);
req.send(fd);
req.onReadyStateChange.listen((Event e) {
if (req.readyState == HttpRequest.DONE &&
(req.status == 200 || req.status == 0)) {
window.alert("upload complete");
}
});
}
InputElement uploadInput = document.querySelector('#sideBar-profile-picture');
uploadInput.onChange.listen((Event event){
// read file content as dataURL
final files = uploadInput.files;
if (files.length == 1) {
File file = files[0];
FileReader reader = new FileReader();
reader.onLoad.listen((e) {
print('results: ${reader.result}');
sendData(reader.result);
});
reader.readAsArrayBuffer(file);
}
});
I have a small server listening for the request (/api/upload) and calling handleUploadRequest with the httpRequest being passed in as the param.
Server code (This is where I am stuck)
Future<Null> handleUploadRequest(final HttpRequest httpRequest) async {
httpRequest.fold(new BytesBuilder(), (b, d) => b..add(d)).then((builder) {
var data = builder.takeBytes();
print('bytes builder: ${data}');
});
}
I am trying to read the data so that I can store it on a cdn but never get a chance to since the connection always gets closed while receiving the data.
Any help on being able to complete this is appreciated. Been at this for the past couple days:/
It is hard to tell when/if you close the httpRequest. If you are doing it right after handleUploadRequest returns, it will indeed close the connection as you are not waiting for httpRequest.fold() to complete. Adding await as shown below and making sure to call httpRequest.close() after this function complete asynchronously should work
Future<Null> handleUploadRequest(final HttpRequest httpRequest) async {
await httpRequest.fold(new BytesBuilder(), (b, d) => b..add(d)).then((builder) {
var data = builder.takeBytes();
print('bytes builder: ${data}');
});
}
(FYI) I have a similar code that works when testing with curl and uploading a file
I need to post a PDF file to a remote REST API, and I can't for the life of me figure it out. No matter what I do, the server responds that I have not yet associated an object with the file parameter. Let's say that I have a PDF called test.pdf. This is what I've been doing so far:
// Using an HttpClientRequest named req
req.headers.contentType = new ContentType('application', 'x-www-form-urlencoded');
StringBuffer sb = new StringBuffer();
String fileData = new File('Test.pdf').readAsStringSync();
sb.write('file=$fileData');
req.write(sb.toString());
return req.close();
Thus far, I've tried virtually every combination and encoding of the data that I write() to the request, but to no avail. I've tried sending it as codeUnits, I've tried encoding it using a UTF8.encode, I've tried encoding it using a Latin1Codec, everything. I'm stumped.
Any help would be greatly appreciated.
You can use MultipartRequest from the http package :
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'john#doe.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new ContentType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Try using the multipart/form-data header rather than x-www-form-urlencoded. This should be used for binary data, also can you show your full req request?
void uploadFile(File file) async {
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "idDocumentOne_1" is a key of the API request
MultipartFile multipartFile = await http.MultipartFile.fromPath(
'idDocumentOne_1',
file.path
);
// add file to multipart
request.files.add(multipartFile);
// send request to upload file
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
I used file picker to pick file.
Here is the codes for pick file.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'],
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.