How to send multipart HTTP requests from browser with Dart - dart

I have to upload an image from browser to my RESTful web API, implemented using Python Eve. From documentation, It requires sending multipart/data-form request. (http://python-eve.org/features.html#file-storage). There is 'dart:http' library that could do. But, it requires 'dart:io', which is not available on browser. So, is there anyway I can send the request from browser?
Thank you for any help.

You can just use something like this:
FormData formData = new FormData();
formData.append('image', '...');
HttpRequest.request('url', method: 'post', sendData: formData).then((HttpRequest request) {
// ...
});
This should set the correct mimeType. If not you can set it with the mimeType parameter.
Regards,
Robert

Client side, the dart:html library should do the trick. Something like this (source):
import 'dart:html';
main() {
InputElement uploadInput = query('#upload');
uploadInput.on.change.add((e) {
// read file content as dataURL
final files = uploadInput.files;
if (files.length == 1) {
final file = files[0];
final reader = new FileReader();
reader.on.load.add((e) {
sendDatas(reader.result);
});
reader.readAsDataURL(file);
}
});
}
/// send data to server
sendDatas(dynamic data) {
final req = new HttpRequest();
req.on.readyStateChange.add((Event e) {
if (req.readyState == HttpRequest.DONE &&
(req.status == 200 || req.status == 0)) {
window.alert("upload complete");
}
});
req.open("POST", "http://127.0.0.1:8080/upload");
req.send(data);
}

Related

How to read file from HTTPRequest on a dart:io server

I am trying to create a server to run locally for my application to upload some files while debugging. It is very simple and the full source code is:
import 'dart:io';
void main(List<String> arguments) async {
const port = 8080;
final server = await HttpServer.bind(InternetAddress.anyIPv4, port);
server.listen((request) async {
if (request.uri.path != '/save_screenshot' || request.method != 'POST') {
request.response.statusCode = 404;
request.response.close();
return;
}
// TODO: read the file
request.response.statusCode = 200;
request.response.close();
});
print('screenshot server listening on $port.');
}
At the code there is a TODO comment, where I would like to read the file from the HTTPRequest, I googled a bit and could not find a example to copy. Does anyone know how to read the file from the HTTPRequest?
Here is how it is being sent (on the client side):
final url = 'http://<local_ip_address>:8080/save_screenshot';
var request = http.MultipartRequest('POST', Uri.parse(url));
request.files.add(
http.MultipartFile.fromBytes(
'file',
screenshot.bytes,
filename: 'screenshot.png',
),
);
await request.send();
I found out how to read the file from the HTTPRequest. But for it to work it is necessary to install a package called mime.
Then replace the TODO comment in the question with:
final boundary = request.headers.contentType!.parameters['boundary']!;
final mimeTransformer = MimeMultipartTransformer(boundary);
final parts = request.cast<List<int>>().transform(mimeTransformer);
await for (final part in parts) {
final file = File('uploaded_files/0.png');
await part.pipe(file.openWrite());
}
I made a gist with the working server: https://gist.github.com/lslv1243/1036364b10c6578d969cb4ed2d7eba42
NOTE: on the gist I changed the path from /save_screenshot to /screenshot

Flutter image_picker post upload an image

I am using the Flutter Plugin Image_picker to choose images so that I want to upload image after selected the image
Future<File> _imageFile;
void _onImageButtonPressed(ImageSource source) async {
setState(() {
_imageFile = ImagePicker.pickImage(source: source);
});
}
I find this code in flutter documentation but its not work
var uri = Uri.parse("http://pub.dartlang.org/packages/create");
var request = new http.MultipartRequest("POST", url);
request.fields['user'] = 'nweiz#google.com';
request.files.add(new http.MultipartFile.fromFile(
'package',
new File('build/package.tar.gz'),
contentType: new MediaType('application', 'x-tar'));
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
});
Use MultipartRequest class
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);
});
}
Check this answer
This code works properly.
Used MultipartRequest class
void uploadImage() async {
File _image;
File pickedImage = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = pickedImage;
});
// open a byteStream
var stream = new http.ByteStream(DelegatingStream.typed(_image.openRead()));
// get file length
var length = await _image.length();
// 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 "image_file" is a key of the API request
var multipartFile = new http.MultipartFile('image_file', stream, length, filename: basename(_image.path));
// add file to multipart
request.files.add(multipartFile);
// send request to upload image
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
name spaces:
import 'package:path/path.dart';
import 'package:async/async.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
If you want the uploading function to return the server response, you can use toBytes() instead of transform(), in order to wait until data transmission is complete.
Future<String> upload() async {
String responseString = '';
// Pick image
final image = await ImagePicker().getImage(
source: ImageSource.gallery // or ImageSource.camera
imageQuality: 100,
maxWidth: 1000,
);
// Convert to File
final file = File(image.path);
// Set URI
final uri = Uri.parse('URL');
// Set the name of file parameter
final parameter = 'Name';
// Upload
final request = http.MultipartRequest('POST', uri)
..files.add(await http.MultipartFile.fromPath(parameter, file.path));
final response = await request.send();
if (response.statusCode == 200) {
responseString = String.fromCharCodes(await response.stream.toBytes());
}
return responseString;
}

Convert String to GET request Parameter in Dart using standard library

I have a multiword String that I'd like to convert to a GET request parameter.
I have an API endpoint /search that takes in the parameter query. Now typically your request would look like http://host/search?query=Hello+World.
I have a String Hello World that I'd like to convert to this URL encoded parameter.
Ofcourse, I could just write the logic to break it into words and add a + in between but I was wondering if the URI class could help with this
I'm using Dart's httpClient to make a request.
Future<String> _getJsonData(String queryToSearch) async {
List data = new List();
var httpClient = new HttpClient();
var request = await httpClient.getUrl(Uri.parse(
config['API_ENDPOINT'] + '/search?query=' +
queryToSearch));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var jsonString = await response.transform(utf8.decoder).join();
data = json.decode(jsonString);
print(data[0]);
return data[0].toString();
} else {
return "{}";
}
}
Essentially, need to encode queryToSearch as the URL parameter.
You can use Uri.http(s) which wrap everythings (query, host, and path) together and encode them accordingly.
final uri = new Uri.http(config['API_ENDPOINT'], '/search', {"query": queryToSearch});
The Uri class provides methods for that
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeQueryComponent.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeFull.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeComponent.html
You can use Uri.parse(url_string) if you have the full URL in this way.
final String accountEndPoint = 'https://api.npoint.io/2e4ef87d9ewqf01e481e';
Future<Account> getAccountData() async {
try {
final uri = Uri.parse(accountEndPoint); // <===
final response = await http.get(uri);
if (response.statusCode == 200) {
Map<String, dynamic> accountJson = jsonDecode(response.body);
return Future.value(Account.fromJson(accountJson));
} else {
throw Exception('Failed to get account');
}
} catch (e) {
return Future.error(e);
}
}

Pass through the HTTP response to the client in MVC 6

I am new to Web API and HTTP.
I am using the MVC 6 (beta version). I have a proxy service (Web API) which has a POST method to get response from another service with XML content returned. I need to return the response content to the client since the client can't call the service directly.
// In my proxy service
public HttpResponseMessage Post(String content)
{
using ( HttpClient client = new HttpClient() ) {
.......
HttpResponseMessage response = client.PostAsync(uri, content).Result;
// I get everything I need in the "response".
// How to return the response or it body to the client.
// return response;
}
}
II need to return the "response" to the client with no or minimum changes. I tried "return response", or create a new HttpResponseMessage, but I only got something like
{"Headers":[{"Key":"Content-Type","Value":["text/xml"]}]}
in the body.
So is there a simple way to pass the response back to the client? Thanks.
The ASP.NET team is currently working on a "proxy middleware" that does exactly what you're looking for: https://github.com/aspnet/Proxy
Here's how it works internally:
public async Task Invoke(HttpContext context)
{
var requestMessage = new HttpRequestMessage();
if (string.Equals(context.Request.Method, "POST", StringComparison.OrdinalIgnoreCase))
{
var streamContent = new StreamContent(context.Request.Body);
requestMessage.Content = streamContent;
}
// Copy the request headers
foreach (var header in context.Request.Headers)
{
if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value) && requestMessage.Content != null)
{
requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
}
requestMessage.Headers.Host = _options.Host + ":" + _options.Port;
var uriString = $"{_options.Scheme}://{_options.Host}:{_options.Port}{context.Request.PathBase}{context.Request.Path}{context.Request.QueryString}";
requestMessage.RequestUri = new Uri(uriString);
requestMessage.Method = new HttpMethod(context.Request.Method);
using (var responseMessage = await _httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead, context.RequestAborted))
{
context.Response.StatusCode = (int)responseMessage.StatusCode;
foreach (var header in responseMessage.Headers)
{
context.Response.Headers.SetValues(header.Key, header.Value.ToArray());
}
foreach (var header in responseMessage.Content.Headers)
{
context.Response.Headers.SetValues(header.Key, header.Value.ToArray());
}
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
context.Response.Headers.Remove("transfer-encoding");
await responseMessage.Content.CopyToAsync(context.Response.Body);
}
}
https://github.com/aspnet/Proxy/blob/dev/src/Microsoft.AspNet.Proxy/ProxyMiddleware.cs

How can we send/get the http headers information with AJAX?

Is there any way to send/get the http headers (like, content-type... ) through AJAX?. Then, can please explain me, what will we archive by passing the http headers in AJAX and where will use this technique?.
Thanks
I'm no expert,
But you should look at the AJAX object XmlHttpHeader and the wikipedia article here.
EDIT: quoting the www.w3.org reference:
function test(data) {
// taking care of data
}
function handler() {
if(this.readyState == 4 && this.status == 200) {
// so far so good
if(this.responseXML != null && this.responseXML.getElementById('test').firstChild.data)
// success!
test(this.responseXML.getElementById('test').firstChild.data);
else
test(null);
} else if (this.readyState == 4 && this.status != 200) {
// fetched the wrong page or network error...
test(null);
}
}
var client = new XMLHttpRequest();
client.onreadystatechange = handler;
client.open("GET", "unicorn.xml");
client.send();
If you just want to log a message to the server:
function log(message) {
var client = new XMLHttpRequest();
client.open("POST", "/log");
client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
client.send(message);
}
Or if you want to check the status of a document on the server:
function fetchStatus(address) {
var client = new XMLHttpRequest();
client.onreadystatechange = function() {
// in case of network errors this might not give reliable results
if(this.readyState == 4)
returnStatus(this.status);
}
client.open("HEAD", address);
client.send();
}

Resources