Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 :
Bulk Edit mode

Key-Value 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)

like image 887
Mathieu Avatar asked May 25 '20 23:05

Mathieu


4 Answers

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.
 }
}
like image 77
Parisa Baastani Avatar answered Oct 18 '22 18:10

Parisa Baastani


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),
);
like image 26
Ali80 Avatar answered Oct 18 '22 20:10

Ali80


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
  }
like image 31
FoggyDay Avatar answered Oct 18 '22 19:10

FoggyDay


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

like image 37
kevintannguyen Avatar answered Oct 18 '22 19:10

kevintannguyen