Not persistent connection for flutter/dart http.Client()

1,987

You don't need a 3rd-party library. It's a fairly small amount of code. So, after a first authorized request, server will respond with a cookie in the response headers, under the key set-cookie. The useful information is in the value of set-cookie key, from the beginning, to the 1st occurrence of the ; character (more on this later). For example, the value of set-cookie might look like this:

sessionid=asfweggv7bet4zw11wfpb4u415yx; expires=Fri, 06 Nov 2020 11:14:40 GMT;

You need to save it and use every time in your next authorized requests.

To save it, I created a method, which you should call after the first authorized response. You can call it after every response (if you have generic response handling), since it won't mess with the existing cookie if the server didn't send a new one.***

import 'package:flutter_secure_storage/flutter_secure_storage.dart';
const kCookie = 'my_fancy_cookie';
// ...
void _storeCookie(http.Response response) async {
  String rawCookie = response.headers['set-cookie'];
  if (rawCookie != null) {
    int index = rawCookie.indexOf(';');
    String cookie = (index == -1) ? rawCookie : rawCookie.substring(0, index);
    await FlutterSecureStorage().write(key: kCookie, value: cookie);
  }
}

And then before I send my request, I add the cookie to headers:

// endpoint, payload and accessToken are defined earlier
cookie = await FlutterSecureStorage().read(key: kCookie);
http.Response response = await http.post(
  endpoint,
  body: json.encode(payload),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer ' + accessToken,
    'cookie': cookie,
  }
);

Remember to clear the cookie from secure storage after logout. :)

*** - Servers might change the session id (to reduce things like clickjacking that we don't need to consider yet), so it's good to keep extracting the cookie from every response.

Share:
1,987
man zet
Author by

man zet

Updated on December 16, 2022

Comments

  • man zet
    man zet over 1 year

    I have a running django-server that works with sessions. A simple example from my views.py that should be enough to reproduce my problem is given here:

    def test(request):
        print("Session objects(")
        for k,v in request.session.items():
            print(k,v)
        print(")")
        request.session["a"] = "b"
    

    So this does just print everything in the current session and after that saving some dummy-data in the session. If I do access this via my browser the first time the output is

    Session objects(
    )
    

    so the session is empty just like expected. Then after refreshing the site the output is:

    Session objects(
    a b
    )
    

    also as expected, so everything seems to work just fine.

    But now I want to use the site with my flutter app. For that I used the flutter packacke import 'package:http/http.dart' as http like this:

    var client = http.Client();
    
    String host = ...; // just the ip:port to my host
    
    void my_request() async {
      var response = await client.get(host + "/path/to/test/");
      response = await client.get(host + "/path/to/test/");
    }
    

    So everything this should do is requesting my site twice just like i did before in the browser manually. But now my server just logges twice:

    Session objects(
    )
    

    So obviously the client has a not persistent connection where the session is not preserved. But according to the doc https://pub.dev/packages/http this should work

    If you're making multiple requests to the same server, you can keep open a persistent connection by using a Client rather than making one-off requests

    is this a problem with my flutter/dart app or is the problem on my server? Is it maybe a big in the flutter package?

    note: I first thought this could be a problem with csrf-authentication so deactivated it on my server, but this doesn't change anything ...

    • kingJulian
      kingJulian about 4 years
      What's the value of the peristenceConnection property? If it's False, try setting it to True and see if that works.