英文:
Not persistent connection for flutter/dart http.Client()
问题
我有一个正在运行的django服务器,它与会话一起工作。我的views.py中的一个简单示例应该足以复现我的问题:
def test(request):
print("Session objects(")
for k, v in request.session.items():
print(k, v)
print(")")
request.session["a"] = "b"
这只是打印当前会话中的所有内容,然后将一些虚拟数据保存在会话中。如果我通过浏览器访问这个页面,第一次的输出是:
Session objects(
)
所以会话为空,正如预期的那样。然后刷新页面后,输出是:
Session objects(
a b
)
也如预期的那样,所以一切似乎都正常工作。
但现在我想在我的Flutter应用程序中使用这个站点。为此,我使用了Flutter包import 'package:http/http.dart' as http
,像这样:
var client = http.Client();
String host = ...; // 只是指向我的主机的IP:端口
void my_request() async {
var response = await client.get(host + "/path/to/test/");
response = await client.get(host + "/path/to/test/");
}
所以这应该做的一切就是像我之前手动在浏览器中一样两次请求我的站点。但现在我的服务器只记录了两次:
Session objects(
)
所以显然客户端有一个不持久的连接,会话没有保留。但根据文档https://pub.dev/packages/http,这应该是可以的。
如果您多次请求同一服务器,可以使用Client保持持久连接,而不是进行一次性请求。
这是我的Flutter/Dart应用程序的问题还是我的服务器的问题?这可能是Flutter包中的一个问题吗?
注意:我起初认为这可能是CSRF身份验证的问题,所以在我的服务器上禁用了它,但这并没有改变什么...
英文:
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:
<!-- begin snippet: js hide: false console: true babel: false -->
def test(request):
print("Session objects(")
for k,v in request.session.items():
print(k,v)
print(")")
request.session["a"] = "b"
<!-- end snippet -->
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
<!-- begin snippet: js hide: false console: true babel: false -->
Session objects(
)
<!-- end snippet -->
so the session is empty just like expected. Then after refreshing the site the output is:
<!-- begin snippet: js hide: false console: true babel: false -->
Session objects(
a b
)
<!-- end snippet -->
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:
<!-- begin snippet: js hide: false console: true babel: false -->
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/");
}
<!-- end snippet -->
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:
<!-- begin snippet: js hide: false console: true babel: false -->
Session objects(
)
<!-- end snippet -->
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 ...
答案1
得分: 1
不需要第三方库。这只是一小部分代码。所以,在第一次授权请求之后,服务器将在响应头中以set-cookie
键的形式响应一个Cookie。有用的信息位于set-cookie
键的值中,从开头到第一个;
字符的出现位置(稍后详细说明)。例如,set-cookie
的值可能如下所示:
sessionid=asfweggv7bet4zw11wfpb4u415yx; expires=Fri, 06 Nov 2020 11:14:40 GMT;
你需要保存它,并在下一次授权请求中使用。
为了保存它,我创建了一个方法,你应该在第一个授权响应之后调用它。如果你有通用的响应处理,你可以在每次响应后调用它(如果服务器没有发送新的Cookie,它不会影响现有的Cookie)。
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);
}
}
然后,在发送请求之前,我将Cookie添加到请求头中:
// endpoint、payload和accessToken在之前已经定义
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,
}
);
记得在注销后从安全存储中清除Cookie。
*** - 服务器可能会更改会话ID(以减少点击劫持等问题,目前我们不需要考虑这些),因此最好从每个响应中不断提取Cookie。
英文:
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.
答案2
得分: 0
浏览器正在保存/发送Django会话cookie。Flutter应用程序的http请求不会。
"持久"连接并不意味着它会为您处理cookies。您需要自己处理它,或者找到一个第三方库来处理。
英文:
The browser is saving/sending the Django session cookie. The flutter app http requests are not.
"Persistent" connection does not mean it will handle cookies for you. You will need to do that yourself or find a third-party library that does it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论