Reputation: 1281
I'm trying to send a post
request in Flutter with DIO
package.
Here is the request:
getSessionId() async {
var csrf = await getCsrftoken();
var dio = new Dio(new Options(
baseUrl: "http://xxxxxxx/accounts/login/",
connectTimeout: 5000,
receiveTimeout: 100000,
// 5s
headers: {
'Cookie': "csrftoken=" + csrf
},
contentType: ContentType.JSON,
// Transform the response data to a String encoded with UTF8.
// The default value is [ResponseType.JSON].
responseType: ResponseType.PLAIN
));
var response;
response = await dio.post("http://xxxxxxx/accounts/login/",
data: {
"username": "xxxxx",
"password": "xxxxx",
"csrfmiddlewaretoken" : csrf
},
options: new Options(
contentType: ContentType.parse("application/x-www-form-urlencoded")),
);
print("StatusCode: ");
print(response.statusCode);
print("Response cookie: "); //THESE ARE NOT PRINTED
print(response.headers);
}
After the request i get:
E/flutter ( 4567): [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
E/flutter ( 4567): DioError [DioErrorType.RESPONSE]: Http status error [302]
E/flutter ( 4567): #0 getSessionId (file:///C:/get_order/lib/main.dart:36:14)
E/flutter ( 4567): <asynchronous suspension>
From this request i only need to get the sessionid
cookie, but the function stop with unhandled exception.
Upvotes: 20
Views: 36542
Reputation: 1869
the solution for me was changing the url form http
to https
because the server was trying to redirects http request to https .
Upvotes: 0
Reputation: 359
I also had this problem, I sent a POST api request using dio library and it returned an error (The request returned an invalid status code of 302)
I issued an identical request using Postman, resulting in a successful response with a status code 200. However, when I attempted the same request in Flutter, it produced an error with a returned status code of 302.
In my case the expected response was the html code of a site I'm being redirected to.
The HTTP
302
error occurs when the requested resource has been temporarily moved to a new location. Hence, the system automatically redirects visitors to a new URL that has the resource.The HTTP redirect starts when the web server hosting the content returns a 3xx status code and a
location header
that holds the new URL. Once the web browser receives this response, it automatically loads the new URL instead of displaying the 404 error not found error.
Source: hostinger.com article
302
error in Flutter using the Dio
package, it means that the server is trying to redirect you to a different site.Dio
package is to automatically follow the redirect via the followRedirects
property and get the HTML response from the redirected site.
But I think it failed to redirect since the request was a POST
, sinceonly "GET" and "HEAD" requests in HttpClientRequest will auto-redirect
as mentioned in dart.dev.
FollowRedirects
and maxRedirects
options in the Options
Dio request like this, to prevent automatic redirects from continuing.final response = await dioClient.post(
// some code
options: Options(
followRedirects: false, // default is true, change to false
maxRedirects: 0, // set to 0
),
);
validateStatus
as follows:Options(
validateStatus: (status) => status! < 500, // or (=> status != null & status < 500 ? true : false), to avoid null exception
),
It is preferable to set these two previous options only for this request without affecting the rest of the requests.
response.headers['location']
like this: String? redirectUrl;
if(response.statusCode == 302){ // check if status code equals 302, then get the redirect url
redirectUrl = '${response.headers['location']}'; // get the redirect URL
}
webview_flutter
.The full code would be like:
final response = await dioClient.post(
// URI here
data: // data here
options: Options(
followRedirects: false,
maxRedirects: 0,
validateStatus: (status) => status! < 500,
),
);
String? redirectUrl;
if(response.statusCode == 302){ // check if status code equals 302, then get the redirect url
redirectUrl = '${response.headers['location']}';
debugPrint('is redirect: ${response.isRedirect}');
log('redirect location: $redirectUrl');
} else if (response.statusCode == 200){
// some code here
}
Upvotes: 1
Reputation: 93
I'm trying to use this to a webscraping... don't ask me why lol. I came from python/golang and I've already tried the http package, however i recommend you to use the dio package.
With dio I'm doing the following:
Scrapers.client = Dio();
// create a local cookie to handle with sites that force you to use it
var cookieJar = CookieJar();
// assign middlewares to be "session like"
Scrapers.client?.interceptors.add(CookieManager(cookieJar));
// assign a logging middleware
Scrapers.client?.interceptors.add(LogInterceptor(responseBody: false));
// set the default content type to this client
Scrapers.client?.options.contentType = Headers.formUrlEncodedContentType;
...
static Future<Response> handleRedirects(Response r, int statusCode) async {
var redirects = 0;
while (r.statusCode == statusCode) {
print("redirect #${redirects++}");
final redirecturl = r.headers['location']![0];
r = await Scrapers.client!.post(redirecturl,
options: Options(
followRedirects: false,
validateStatus: (status) {
return status! < 500;
}));
}
return r;
}
...
Response r = await Scrapers.client!.post(url,
data: payload,
options: Options(
followRedirects: false,
validateStatus: (status) {
return status! < 500;
}));
r = await Scrapers.handleRedirects(r, 302);
Note that it's just a simple approach. You can change it according with you needs.
Upvotes: 1
Reputation: 552
i got a similar problem and i solved it with adding header with "Accept":"application/json" . henceforth it will only return json data otherwise it will prompt to redirect with html url.
Upvotes: 7
Reputation: 1281
I solved this way:
Add followRedirects: false
and validateStatus: (status) { return status < 500;}
to the request. Like this:
var response = await Dio().post("http://myurl",
data: requestBody,
options: Options(
followRedirects: false,
validateStatus: (status) { return status < 500; }
),
);
This way you can get from the 302
every headers
and other.
Upvotes: 30
Reputation: 477
in my case, this problem was solved by send the cookie with the header in the post method
and the problem is the API was response to me with HTML login page rather than JSON data.
and you will find the cookie key in the response header when you perform a si/log - in
and the status error code was 302
Upvotes: 0
Reputation: 435
Redirections for 302 are made in response to GET or HEAD requests, never for POST. Sometimes server sends 302 in response to POST (that was in my case). In this case Dio throws exception you can catch - remember to check if server status code is 302 or maybe it's another error.
try{
await dio.post( _urlLogin,
data:{...},
options: Options(
contentType: ContentType.parse("application/x-www-form-urlencoded"),
)
);
}on DioError catch(error){
if(error.response.statusCode == 302){
// do your stuff here
}
Upvotes: 2
Reputation: 51682
The Dart HTTP client won't follow redirects for POSTs unless the response code is 303. It follows 302 redirects for GET or HEAD.
You could see if you can stop the server sending the redirect in response to a (presumably) valid login request, and send a 200 instead.
Or you could try sending the login request as a GET by encoding the form fields into the URL, for example:
http://xxxxxxx/accounts/login/?username=xxxx&password=yyyy&csrfmiddlewaretoken=zzzz
You would have to URL encode any special characters in the parameters. Presumably, you'll want to use HTTPS too.
Finally, is the URL meant to end with /
? It might be worth trying /accounts/login
.
Upvotes: 6