You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter对接FastAPI /token JWT登录接口报422错误如何解决

问题根因

FastAPI 内置的 OAuth2PasswordRequestForm 强制要求请求使用 application/x-www-form-urlencoded 表单格式传参,不接收 application/json 格式的请求体。你在 Flutter 端用 Dio 发请求时默认传的是 JSON 格式参数,和后端要求的格式不匹配,所以后端解析不到 username 字段,返回422参数缺失错误。Postman/Insomnia 能调通是因为工具默认选对了表单传参格式。

除此之外你的代码还有4处逻辑错误,会导致后续token存储、鉴权失效:

  • TokenManager 拦截器给请求加的鉴权头字段名、格式不符合JWT标准
  • 拦截器判断token返回值的字段名和后端实际返回的字段不匹配,登录成功后token不会被存储
  • 缺少token清理方法,401场景下无法清除本地过期token
  • 登录状态检查逻辑错误,对仅支持POST的/token接口发GET请求
  • 未调用token初始化方法,应用重启后本地存储的token不会被加载
修复方案

1. 修改登录请求传参格式

替换login.dart中登录请求的代码,指定请求为表单编码格式:

var response = await DioClient.dio.post(
  'http://10.0.2.2:8000/token',
  data: {
    "username": _username,
    "password": _password,
  },
  // 关键:指定内容类型为表单urlencoded格式
  options: Options(
    contentType: Headers.formUrlEncodedContentType,
  ),
);

注意:不要对data做jsonEncode处理,Dio会自动按指定格式编码参数

2. 修复TokenManager的鉴权头逻辑

修改Dio_token_manager.dart中的onRequest方法,使用标准JWT鉴权头格式:

@override
void onRequest(
  RequestOptions options,
  RequestInterceptorHandler handler,
) {
  if (_token != null) {
    // 标准OAuth2 JWT鉴权头格式
    options.headers['Authorization'] = 'Bearer $_token';
  }
  return super.onRequest(options, handler);
}

3. 修复token存储逻辑

修改onResponse方法,匹配后端实际返回的access_token字段,同时补全缺失的clearToken方法:

@override
void onResponse(
  Response response,
  ResponseInterceptorHandler handler,
) {
  // 识别登录接口返回,存储token
  if (response.requestOptions.path.endsWith('/token') && response.statusCode == 200) {
    final resData = response.data;
    if (resData['access_token'] != null) {
      saveToken(resData['access_token']);
    }
  } else if (response.statusCode == 401) {
    clearToken();
  }
  super.onResponse(response, handler);
}

// 补全缺失的清除token方法
Future<void> clearToken() async {
  _token = null;
  SharedPreferences prefs = await SharedPreferences.getInstance();
  prefs.remove('token');
}

4. 修正初始化和登录状态检查逻辑

  • 在initState添加token初始化调用:await TokenManager.instance.initToken();
  • 不要向/token接口发GET请求检查登录状态,应该调用需要鉴权的业务接口(比如获取当前用户信息接口),如果返回200说明token有效,返回401说明未登录/登录过期。
验证结果

改完后重新运行应用,点击登录即可正常拿到200响应,token会自动持久化存储,后续所有请求会自动携带合法鉴权头。


内容的提问来源于stack exchange,提问作者pythonGo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:51:22