Why flutter http response in web missing headers? - flutter

I am making a simple flutter app using http package.
I am trying to send a (post) login request, and the httpresponse is missing all the headers!
this works fine in ios simulator but in chrome as you can see there are only 2 headers available;
What is wrong?
Thanks

I have the following:
Response headers web:
"Origin":"http://localhost:57986"
Example code:
Future<File> downloadFile(String url, String pathFile) async {
File file = new File(pathFile);
var request = await http.post(Uri.parse(url), encoding: Encoding.getByName('utf8'), headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS, PUT, DELETE, HEAD",
});
if (request.statusCode == 200) {
Map<String, String> headers = request.headers;
if (headers.containsKey("Origin")) {
var origin = headers['Origin'];
print("your result: " + origin.toString());
}
file.writeAsBytes(request.bodyBytes);
}
return file;
}

Related

POST call works on Postman but not on Flutter

Future<String> loginUser(User user) async {
var body = jsonEncode({
'strlogin': user.email,
});
Response response = await post(SeguriSignAPIURL.loginUser,
headers: headers,
body: body);
if (response.statusCode == 200) {
var decode = jsonDecode(response.body);
return decode['token'];
} else {
print(response.reasonPhrase);
return '';
}
Hey! When I make this Post call on Postman I get a result, however when I run this code on flutter I get a 400 error. My headers:
final headers = {
'Content-Type': 'application/json; charset=UTF-8',
"Accept": "application/json",
};
Postman:
In Postman you do the request using form-data, but in your Flutter code, you pass json-encoded body.
You either need to use form-data in Flutter or update your server code to accept json content type.

how to send an object in formdata flutter

I am currently working on a mobile app and I am stuck in this for days now. I have been trying to send a post request to create an object "Leave" as represents the code below. The request body is formData with a key 'leave' and value 'jsonObject'.I've tried a lot of methods and it has a relation with 'Content-type'I suppose. If i change it to 'multipart/form-data' the response becomes 500 and if it is 'application/json' i always get 415 unsupported mediaType. This is my code using dio package, any advice would be helpful guys, thank u on advance.Postman request works fine
Future createLeave() async {
var leave = Conge(
dateDemand: DateTime.now(),
dateEnd: DateTime.now().add(Duration(days: 3)),
dateStart: DateTime.now().add(Duration(days: 1)),
type: "CSS",
endDateDaySlot: "X",
startDateDaySlot: "X",
);
Map<String, String> heads = {
"X-Auth-Token": UserPreferences().token,
"Content-type": 'application/json',
"accept": "application/json"
};
FormData formData = FormData.fromMap({"leave": leave.toJson()});
var dio = Dio();
try {
Response response = await dio.post(API + '/leave/add',
data: formData,
options:
Options(headers: heads, contentType: Headers.jsonContentType));
} on Exception catch (e) {
print(e);
}
}
I have also tried to use MultiPartRequest but i always get 400 as a response, the request sent by the client was syntactically incorrect here is my code could anyone help me with this please
Future create(Conge leave) async {
String url = API + "/leave/add";
var uri = Uri.parse(url);
var request = new http.MultipartRequest("POST", uri);
Map<String, String> heads = {
"X-Auth-Token": UserPreferences().token,
"Content-type": 'application/json',
};
request.headers.addAll(heads);
request.fields['leave'] = json.encode(leave.toJson());
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}
Please try to disable the firewall of windows, if it works then make an exception for it in the firewall.

How to send a png file by 'application/octet-stream' in Dart/Flutter to Microsoft Custom Vision?

I know this question could be redundant, but I am trying to send a png file through a POST request to Microsoft Custom Vision in Flutter.
This is my code:
void _makeRequest (File file) async {
String url = "<url>";
Map<String, String> headers = {
"Content-Type": "application/octet-stream",
"Prediction-Key": "<key>",
};
var bytes = file.readAsBytesSync();
var response = await http.post(
url,
headers: headers,
body: bytes,
);
print(response.body);
print(response.statusCode);
}
And when I run this code I get this response:
{"code":"ErrorUnknown","message":"The request entity's media type 'appliction/octet-stream' is not supported for this resource."}
Based on your comment , I think you used the wrong endpoint/URL. Since you're sending image, you have to use the other prediction endpoint that looks like this:
"https://southcentralus.api.cognitive.microsoft.com/customvision/v3.0/Prediction/<Project ID>/classify/iterations/<Iteration number>/image
^ Note ../image
If still can't, please try below code snipper(works for me):
final bytes = file.readAsBytesSync();
var uri = Uri.parse(
"<Prediction endpoint>");
var request = new http.Request("POST", uri)
..headers['Prediction-Key'] = "<Prediction Key>"
..headers['Content-Type'] = "application/octet-stream"
..bodyBytes = bytes;
http.Response response = await http.Response.fromStream(await request.send());
print(request);
print("Result: ${response.statusCode}");
print(response.statusCode);
print(response.body);

How to post x-www-form-urlencoded in Flutter

I am trying to send a POST request to an API to create an account.
The request is working well, it should look like this :
Bulk Edit Mode :
Key-Value Edit mode :
There are also 9 headers that are auto-generated, so I did not show them, but I can take another screen if you need to.
My request looks like this :
import 'dart:convert' as convert ;
import 'package:my_project/requests/utils.dart';
import 'package:http/http.dart' as http;
Future<String> createUser(String firstName, String name, String mail,
String password, String confirmPassword, String birthDate,
String phone) async {
String url = BASE_URL + "createUser" ; // Don't worry about BASE_URL, the final url is correct
Map<String, dynamic> formMap = {
"name": name,
"surname": firstName,
"mail": mail,
"password": password,
"birth": birthDate,
"phone": phone,
"confirmPassword": confirmPassword
} ;
http.Response response = await http.post(
url,
body: convert.jsonEncode(formMap),
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
encoding: convert.Encoding.getByName("utf-8"),
);
print("RESPONSE ${response.statusCode} ; BODY = ${response.body}");
return (response.body) ;
}
Here is my print result :
I/flutter ( 6942): RESPONSE 307 ; BODY =
As you can see, I am getting a 307 error, and the problem does not come from the server, as it worked with Postman.
Am I sending this form-urlencoded POST request correctly ?
I also tried :
http.Response response = await http.post(
url,
body: "name=$name&surname=$firstName&mail=$mail&password=$password&birth=$birthDate&phone=$phone&confirmPassword=$confirmPassword",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
encoding: convert.Encoding.getByName("utf-8"),
);
but with the same results. I tried too :
http.Response response = await http.post(
url,
body: formMap,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
encoding: convert.Encoding.getByName("utf-8"),
);
with same result again.
What am I doing wrong ?
EDIT :
I tried FoggyDay answer, here is my request now :
final client = HttpClient() ;
final request = await client.postUrl(Uri.parse(url));
request.headers.set(HttpHeaders.contentTypeHeader, "application/x-www_form-urlencoded");
request.followRedirects = true ;
request.write(formMap);
final response = await request.close();
print("STATUS CODE = ${response.statusCode}");
However I still have a 307 error. Did I create the right request ?
EDIT 2 :
As asked, I printed location as follow :
final client = HttpClient() ;
final request = await client.postUrl(Uri.parse(url));
request.headers.set(HttpHeaders.contentTypeHeader, "application/x-www_form-urlencoded");
request.followRedirects = true ;
request.write(formMap);
final response = await request.close();
print("STATUS CODE = ${response.statusCode}");
print("Response headers = ${response.headers}");
And I get :
I/flutter ( 7671): STATUS CODE = 307
I/flutter ( 7671): Response headers = location: /app/createUser/
I/flutter ( 7671): date: Tue, 26 May 2020 09:00:29 GMT
I/flutter ( 7671): content-length: 0
I/flutter ( 7671): server: Apache/2.4.41 (Amazon) OpenSSL/1.0.2k-fips
The thing is I am already making a call on /app/createUser... ('/app/' is in BASE_URL)
For x-www-form-urlencoded parameters, just use this:
Future<String> login(user, pass) async {
final response = await http.post(
Uri.parse('https:youraddress.com/api'),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
encoding: Encoding.getByName('utf-8'),
body: {"title": "title"},
);
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
}
}
official http package from flutter is buggy with urlencoded type, you can use Dio package instead.
final dio = Dio();
final res = dio.post(
'/info',
data: {'id': 5},
options: Options(contentType: Headers.formUrlEncodedContentType),
);
As you can see, I am getting a 307 error, and the problem does not come from the server, as it worked with Postman.
No, that's NOT necessarily the case. Look here:
MDN: 307 Temporary Redirect
In other words, Postman is following the redirect ... and your Flutter app isn't.
SUGGESTION: Try setting followRedirects to true:
https://api.flutter.dev/flutter/dart-io/HttpClientRequest/followRedirects.html
ADDITIONAL INFO:
The default value for request.followRedirects happens to be "true" anyway. It doesn't hurt to explicitly set it ... but it explains why the behavior didn't change.
Per this post:
The Dart HTTP client won't follow
redirects
for POSTs unless the response code is 303. It follows 302 redirects
for GET or HEAD.
Per this post
The correct way to handle redirects on POST requests is to manually
implement an appropriate strategy for your use case:
var response = await client.post(...);
if (response.statusCode == 301 || response.statusCode == 302) {
// send post request again if appropriate
}
let try with this code, it works well for me.
var headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var request = http.Request('POST', Uri.parse('https://oauth2.googleapis.com/token'));
request.bodyFields = {
'client_id': '',
'client_secret': '',
'code': '',
'grant_type': 'authorization_code',
'redirect_uri': ''
};
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
If you are using http, you should add the below lines
Android -
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="first_app"
android:usesCleartextTraffic="true" //this line
android:icon="#mipmap/ic_launcher">
iOS -
ios/Runner/info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Be warned that you will need to have an explanation for Apple's review team when enabling this, otherwise, your app will get rejected on submission.
Uninstall the app and Reinstall again if you have the app already in the emulator when you add those lines to avoid confusions.
If you send HTTP GET request, you can use query parameters as follows:
QueryParameters
http://example.com/path/to/page?name=ferret&color=purple
The contents are encoded as query parameters in the URL
application/x-www-form- urlencoded
The contents are encoded as query parameters in the body of the
request instead of the URL.
The data is sent as a long query string. The query string contains
name-value pairs separated by & character
POST example
flutter http package version - http: ^0.13.1
import 'package:http/http.dart' as httpClient;
Future<dynamic> postData() async {
//Uri.https("192.168.1.30:5000", "/api/data")
//Uri.parse("your url");
final Uri uri = Uri.http("192.168.1.30:5000", "/api/data");
final response = await httpClient.post(
uri,
body: {
"name": "yourName",
"age": "yourAge"
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
encoding: Encoding.getByName('utf-8'),
);
return response.body;
}

Flutter http Package POST API call return 302 instead of 200, post is success in DB

Hi when I make an API post request via Postman getting the correct status code as 200 but make the same api call with flutter/http package (v0.12.0+4) or DIO (v3.0.9) package I'm getting status code as 302, but the post was successful and the data was saved on the DB. how can I get the status 200 for this or is there a better way to handle redirect in post
Found these git hub issues, but no answer on how to fix this
https://github.com/dart-lang/http/issues/157
https://github.com/dart-lang/sdk/issues/38413
Code making API post
...........
final encoding = Encoding.getByName('utf-8');
final headers = {
HttpHeaders.contentTypeHeader: 'application/json; charset=UTF-8',
HttpHeaders.acceptHeader: 'application/json',
};
//String jsonBody = jsonEncode(feedRequest.toJsonData());
String jsonBody = feedRequest.toJsonData();
print('response.SubmitFeedApiRequest>:' + feedRequest.toJsonData());
print('jsonBody:>' + jsonBody);
String url ='https://myapp';
final response = await http.post(url,
headers: headers, body: jsonBody, encoding: encoding);
print('response.statusCode:' + response.statusCode.toString());
if (response.statusCode == 200) {
print('response.data:' + response.body);
} else {
print('send failed');
}
...............
Postman Screenshot
===UPDATED WORKING CODE AS PER #midhun-mp comment
final response = await http.post(url,
headers: headers, body: jsonBody, encoding: encoding);
print('response.statusCode:' + response.statusCode.toString());
if (response.statusCode == 302) {
//print('response.headers:' + response.headers.toString());
if (response.headers.containsKey("location")) {
final getResponse = await http.get(response.headers["location"]);
print('getResponse.statusCode:' + getResponse.statusCode.toString());
return SubmitFeedApiResponse(success: getResponse.statusCode == 200);
}
} else {
if (response.statusCode == 200) {
// print('response.data:' + response.body);
return SubmitFeedApiResponse.fromJson(json.decode(response.body));
}
return SubmitFeedApiResponse(success: false);
}
}
Just add additional header,
header : "Accept" : "application/json"
The 302 is not an error, it's a redirection status code. The http package won't support redirection for POST request.
So you have to manually handle the redirection. In your code you have to add a condition for status code 302 as well. When the status code is 302, look for the redirection url in the response header and do a http GET on that url.