Flutter Web中Set-Cookie未出现在响应头的问题求助
问题描述
调用登录API后出现以下异常情况:
- Chrome开发者工具网络面板能看到服务器返回的Cookie
- 代码打印的响应头日志里找不到
Set-Cookie字段 - ChromeApplication > Cookies面板里完全看不到这个Cookie
我们用Flutter的dio包发起网络请求,核心请求代码如下:
static Future<void> request({ required HttpMethod? method, bool hideLoadingIndicator = false, required String? path, required Map? params, required BuildContext context, required OnResponse onResponse, }) async { try { if (!hideLoadingIndicator) { showLoading(context); } Response response; switch (method) { case HttpMethod.post: response = await DioFactory.dio!.post( path!, options: Options(headers: { HttpHeaders.contentTypeHeader: "application/json", }), data: params, ); break; case HttpMethod.delete: response = await DioFactory.dio!.delete( path!, data: params, ); break; case HttpMethod.get: response = await DioFactory.dio!.get( path!, ); break; case HttpMethod.patch: response = await DioFactory.dio!.patch( path!, data: params, ); break; case HttpMethod.put: response = await DioFactory.dio!.put( path!, options: Options(headers: { HttpHeaders.contentTypeHeader: "application/json", }), data: params, ); break; default: return; } print("----whole response----->>>>>>> $response"); print("------rawCookies--->>>>>>> ${response.headers.map}"); if (!hideLoadingIndicator) { hideLoading(context); } if (response.statusCode == 401) { showSessionDialog(context); } else if (response.data["success"] == 0) { List errors = response.data['error']; if (errors.isNotEmpty) { handleApiError(errors.first ?? "", context); } else { handleApiError("Something went wrong! Please try again.", context); } } else { onResponse(response.data); } } catch (e) { if (!hideLoadingIndicator) { hideLoading(context); } String errorMessage = ""; if (e is DioError) { if (e.type == DioErrorType.connectTimeout || e.type == DioErrorType.sendTimeout || e.type == DioErrorType.receiveTimeout || e.type == DioErrorType.other) { errorMessage = 'Server unreachable'; } else if (e.type == DioErrorType.response) { if (e.response!.statusCode == 401) { PrefUtils.clearPrefs(); } else { final response = e.response; List errors = response?.data['error']; if (errors.isNotEmpty) { errorMessage = errors.first; } else { errorMessage = "Something went wrong! Please try again."; } } } else { errorMessage = "Request cancelled"; } } else { errorMessage = e.toString(); } handleApiError(errorMessage, context); } }
排查方向及解决办法
1. Dio未配置Cookie管理器(最常见原因)
Dio默认不会自动处理Cookie的解析、存储和携带,必须手动添加CookieManager拦截器,否则哪怕服务器返回了Set-Cookie,也不会被处理。
解决步骤:
- 在
pubspec.yaml中添加依赖:
dependencies: cookie_jar: ^4.0.1 # 版本号以最新发布版为准
- 修改Dio初始化代码,加入Cookie管理器:
import 'package:dio/dio.dart'; import 'package:cookie_jar/cookie_jar.dart'; class DioFactory { static Dio? dio; static void init() { dio = Dio(); // 用PersistentCookieJar可实现Cookie持久化,重启APP不会丢失 CookieJar cookieJar = PersistentCookieJar(); dio!.interceptors.add(CookieManager(cookieJar)); } }
2. 跨域请求未开启Credentials
如果请求是跨域的(前端域名与后端API域名不一致),必须同时满足两个条件:
- 服务器响应头包含
Access-Control-Allow-Credentials: true,且Access-Control-Allow-Origin不能设为*,必须是具体的前端域名 - Dio请求时开启
withCredentials: true
修改请求代码:
在每个请求的Options中添加withCredentials: true,以POST请求为例:
response = await DioFactory.dio!.post( path!, options: Options( headers: { HttpHeaders.contentTypeHeader: "application/json", }, withCredentials: true, // 新增此行 ), data: params, );
3. 响应头打印方式错误
Dio内部会将响应头的键统一转为小写,所以直接打印response.headers.map可能看不到Set-Cookie,需要改为打印小写的set-cookie:
print("------Set-Cookie--->>>>>>> ${response.headers['set-cookie']}");
4. 服务器返回的Cookie属性限制
Chrome Application面板不显示Cookie,可能是Cookie自身属性导致:
- HttpOnly:标记为
HttpOnly的Cookie,浏览器Application面板不会显示,但Dio的Cookie管理器依然能处理,后续请求会自动携带 - SameSite:若设置为
Strict或Lax,跨域请求时不符合规则的话,浏览器会拒绝存储 - Domain/Path:Cookie的Domain设置与当前页面域名不匹配,或Path设置过于严格
可在Chrome网络面板的对应请求中,查看Response Headers的Set-Cookie详情,检查这些属性是否正常。
总结
优先检查Dio的Cookie管理器配置,这是最容易忽略的点;再确认跨域请求的Credentials设置;最后验证服务器返回的Cookie属性是否符合规则。
内容的提问来源于stack exchange,提问作者Mustafa Lokhandwala
相关产品推荐
相关产品推荐

