Flutter&Dio空安全改造后API客户端遇400 Bad Request问题求助
排查Flutter调用dj-rest-auth登录接口400错误的方案
400 Bad Request本质是后端判定请求不符合要求,结合你是适配空安全代码后出现的问题,从以下方向逐一排查:
1. 先获取后端返回的具体错误细节
Django日志仅显示400,但响应体的42字节内容必然包含具体错误(比如参数为空、格式不匹配)。在login请求的回调里添加打印:
.then((response) { print('登录响应详情: ${response.data}'); // 关键:看后端给出的具体错误提示 // 原有逻辑代码... }) .catchError((err) { print('请求异常信息: $err'); });
常见错误如{"non_field_errors": ["无法使用提供的凭据登录"]}或{"email": ["此字段为必填项"]},能直接定位问题根源。
2. 确保请求参数非空且格式合规
当前login方法的password和email参数无类型约束,空安全改造后很可能传入null值,导致请求体字段为空触发后端验证失败。修改方式:
- 给参数添加非空类型与必填约束:
void login({required String password, required String email, required Function(LoginResponse) callback}) { print('传入参数校验: email=$email, password=$password'); // 先确认参数不为空 // 原有请求逻辑... }
调用时必须传入非空字符串,避免null被传递到后端。
3. 对齐请求头与数据格式和dj-rest-auth要求
dj-rest-auth默认接收application/json格式请求,虽Dio默认已设置,但可显式指定确保无偏差:
_dio.post( API_HOST + "dj-rest-auth/login/", data: { 'email': email, 'password': password, }, options: Options( validateStatus: (status) => status! < 500, contentType: Headers.jsonContentType, // 显式声明JSON格式 ), )
同时对比Postman的请求:检查Postman的Content-Type、请求体格式,若Postman用form-data,Flutter需对应改为data: FormData.fromMap(...)。
4. 添加Dio日志拦截器,监控实际请求细节
通过日志拦截器查看完整请求信息(请求头、请求体、响应),和Postman请求做对比:
// 初始化Dio时添加拦截器 _dio.interceptors.add(LogInterceptor( requestBody: true, responseBody: true, requestHeader: true, ));
控制台会打印所有请求细节,能快速找出和Postman请求的差异点。
5. 简化代码排查空安全逻辑干扰
先写极简测试请求,确认参数和格式无问题:
void testLogin() { _dio.post( API_HOST + "dj-rest-auth/login/", data: { 'email': '你的测试邮箱', 'password': '你的测试密码', }, ).then((res) { print('测试响应: ${res.statusCode}, ${res.data}'); }).catchError((err) { print('测试错误: $err'); }); }
若测试成功,说明问题出在原有空安全逻辑(如AuthTokens.fromJson解析错误、callback参数处理);若仍返回400,则是请求本身的参数/格式问题。
修复后的login代码示例
void login({required String password, required String email, required Function(LoginResponse) callback}) { print('登录参数校验: email=$email, password=$password'); _dio.post( API_HOST + "dj-rest-auth/login/", data: { 'email': email, 'password': password, }, options: Options( validateStatus: (status) => status! < 500, contentType: Headers.jsonContentType, ), ).then((response) { print('登录响应: ${response.statusCode}, ${response.data}'); AuthTokens? authTokens; if (response.statusCode == 200) { try { authTokens = AuthTokens.fromJson(response.data); } catch (e) { print('解析AuthTokens失败: $e'); } } if (authTokens != null) { authTokens.save(); callback(LoginResponse(response.statusCode, authTokens)); } else { print('登录失败或令牌解析失败'); // 可补充:给callback传递失败状态,比如LoginResponse(response.statusCode, null) } }).catchError((error) { print('请求出错: $error'); }); }
内容的提问来源于stack exchange,提问作者kokserek
相关产品推荐
相关产品推荐

