I'd like to make an http request to a remote server while properly handling cookies (eg. storing cookies sent by the server, and sending those cookies when I make subsequent requests). It'd be nice to preserve any and all cookies
for http request I am using
static Future<Map> postData(Map data) async { http.Response res = await http.post(url, body: data); // post api call Map data = JSON.decode(res.body); return data; }
Especially if your flutter web application is not running in the same domain as the server where you api is running. Even if its on the same machine, you will have to allow the request from certain domain and ports. If you are not aware of CORS you can read here.
The Flutter Web application send a HTTP REST API POST request and gets back a JSON response and a cookie in the Set-Cookie header as follows. The server side runs on ASPNet. Core 3.1 in a Docker container, however it should not be an issue, since the cookie is there in the header.
Here's an example of how to grab a session cookie and return it on subsequent requests. You could easily adapt it to return multiple cookies. Make a Session
class and route all your GET
s and POST
s through it.
class Session { Map<String, String> headers = {}; Future<Map> get(String url) async { http.Response response = await http.get(url, headers: headers); updateCookie(response); return json.decode(response.body); } Future<Map> post(String url, dynamic data) async { http.Response response = await http.post(url, body: data, headers: headers); updateCookie(response); return json.decode(response.body); } void updateCookie(http.Response response) { String rawCookie = response.headers['set-cookie']; if (rawCookie != null) { int index = rawCookie.indexOf(';'); headers['cookie'] = (index == -1) ? rawCookie : rawCookie.substring(0, index); } } }
I have improved the Richard Heap's solution to be capable to process multiple 'Set-cookies' and multiple cookies.
In my case, the server returns multiples 'Set-cookies'. The http package concatenate all the set-cookies headers in one header and separate it by comma (',').
class NetworkService { final JsonDecoder _decoder = new JsonDecoder(); final JsonEncoder _encoder = new JsonEncoder(); Map<String, String> headers = {"content-type": "text/json"}; Map<String, String> cookies = {}; void _updateCookie(http.Response response) { String allSetCookie = response.headers['set-cookie']; if (allSetCookie != null) { var setCookies = allSetCookie.split(','); for (var setCookie in setCookies) { var cookies = setCookie.split(';'); for (var cookie in cookies) { _setCookie(cookie); } } headers['cookie'] = _generateCookieHeader(); } } void _setCookie(String rawCookie) { if (rawCookie.length > 0) { var keyValue = rawCookie.split('='); if (keyValue.length == 2) { var key = keyValue[0].trim(); var value = keyValue[1]; // ignore keys that aren't cookies if (key == 'path' || key == 'expires') return; this.cookies[key] = value; } } } String _generateCookieHeader() { String cookie = ""; for (var key in cookies.keys) { if (cookie.length > 0) cookie += ";"; cookie += key + "=" + cookies[key]; } return cookie; } Future<dynamic> get(String url) { return http.get(url, headers: headers).then((http.Response response) { final String res = response.body; final int statusCode = response.statusCode; _updateCookie(response); if (statusCode < 200 || statusCode > 400 || json == null) { throw new Exception("Error while fetching data"); } return _decoder.convert(res); }); } Future<dynamic> post(String url, {body, encoding}) { return http .post(url, body: _encoder.convert(body), headers: headers, encoding: encoding) .then((http.Response response) { final String res = response.body; final int statusCode = response.statusCode; _updateCookie(response); if (statusCode < 200 || statusCode > 400 || json == null) { throw new Exception("Error while fetching data"); } return _decoder.convert(res); }); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With