Flutter Dio POST请求始终返回419错误,Laravel后端返回200
问题描述
使用Flutter开发跨平台网页,对接Laravel后端时遭遇419错误:
- Laravel后端日志显示登录请求返回200状态码,但Flutter端始终收到419错误,无法进入成功逻辑
- 使用Dio ^5.1版本,Postman测试登录请求可正常完成,Flutter已配置IPv4地址作为BaseUrl,排除了127.0.0.1、10.0.0.2这类地址问题
相关代码
login_controller.dart
void submitLogin() async { try { bool isValid = await validateEmail(inputUser.text); if (isValid) { await api.call( { "email": inputUser.text, "password": inputPass.text, }, endpoint: '/login', method: 'POST', ); } else { showSnackbar(msg: "Algo errado, favor validar os dados inseridos.", type: 0); } } catch (e) { showSnackbar(msg: e.toString(), type: 0); Get.back(); } }
api.call函数代码
Future<Response?> call(Map<String, dynamic> data, {required String endpoint, required String method}) async { try { if (token.value == "") { await getToken(); } options.headers.addIf(token.value != "", 'token', token.value); if (method == "GET") { Response getResponse = await dio.get(endpoint); print(getResponse.statusCode); return getResponse; } if (method == "POST") { Response postResponse = await dio.post(endpoint, data: jsonEncode(data.values)); print(postResponse.statusCode); return postResponse; } } on DioError catch (e) { print(e.response); showSnackbar(msg: e.toString(), type: 0); } }
解决方案
419错误在Laravel中本质是CSRF令牌验证失败,结合你的代码场景,问题出在以下几点:
1. POST请求参数格式错误
你在POST请求中使用jsonEncode(data.values),会将参数转为数组格式(如["xxx@xxx.com", "123456"]),但Laravel登录接口需要键值对结构的JSON(如{"email":"xxx@xxx.com","password":"123456"})。直接传入data即可,Dio会自动处理JSON编码:
Response postResponse = await dio.post(endpoint, data: data);
2. 缺少CSRF令牌及Cookie管理
Laravel默认要求POST请求携带CSRF令牌,Postman能成功是因为它自动保存了Laravel的Session Cookie,而Flutter端需要手动处理:
- 先请求Laravel的
/csrf-cookie接口,获取CSRF令牌(该接口会返回Set-Cookie头) - 将令牌放入请求头的
X-CSRF-TOKEN字段(而非你当前用的token字段) - 给Dio配置Cookie管理器,确保能保存Session Cookie
修改后的api.call函数示例:
import 'package:dio_cookie_manager/dio_cookie_manager.dart'; import 'package:cookie_jar/cookie_jar.dart'; // 初始化Dio时配置Cookie管理器 final dio = Dio(); final cookieJar = CookieJar(); dio.interceptors.add(CookieManager(cookieJar)); Future<Response?> call(Map<String, dynamic> data, {required String endpoint, required String method}) async { try { // 非GET请求先获取CSRF令牌 if (method != "GET") { await dio.get('/csrf-cookie'); } // 从Cookie中提取CSRF令牌 List<Cookie> cookies = await cookieJar.loadForRequest(Uri.parse("你的LaravelBaseUrl/csrf-cookie")); String? csrfToken = cookies.firstWhere((cookie) => cookie.name == 'XSRF-TOKEN', orElse: () => Cookie('', '')).value; if (csrfToken != "") { options.headers['X-CSRF-TOKEN'] = csrfToken; } if (method == "GET") { Response getResponse = await dio.get(endpoint); print(getResponse.statusCode); return getResponse; } if (method == "POST") { Response postResponse = await dio.post(endpoint, data: data); print(postResponse.statusCode); return postResponse; } } on DioError catch (e) { print(e.response); showSnackbar(msg: e.toString(), type: 0); } }
3. 检查Content-Type请求头
如果手动编码JSON,需确保请求头Content-Type设为application/json,不过直接传入Map给Dio时,它会自动设置该头,无需额外操作。
内容的提问来源于stack exchange,提问作者Psychobellic
相关产品推荐
相关产品推荐

