Flutter中Dio发起post请求仅触发onRequest无响应如何解决
问题根因
- 核心问题是请求头声明的内容类型和实际提交的请求体格式不匹配:你在请求头中明确设置
Content-Type为application/x-www-form-urlencoded(表单编码格式),但实际传入data参数的是json.encode()序列化后的JSON字符串,二者格式完全不兼容。 - Dio内部会根据你设置的
Content-Type选择对应的请求体编码逻辑:当识别到application/x-www-form-urlencoded类型时,默认要求传入Map<String, dynamic>类型的表单数据,会自动完成表单格式编码。你传入序列化后的字符串会导致编码逻辑异常,要么请求发出后服务端无法识别格式挂起连接,要么Dio内部处理请求时卡住,因此只会触发拦截器的onRequest回调,无法进入onResponse流程。 - 次要排查点:如果自定义了请求拦截器,检查
onRequest方法中是否正确调用handler.next(requestOptions)放行请求,若拦截器逻辑中没有执行放行操作,请求会一直处于pending状态不会发出。但你已确认Postman调用接口正常,该问题出现概率极低。
解决方案
根据接口实际要求的数据格式二选一调整即可:
- 若接口要求提交
x-www-form-urlencoded表单格式:
移除json.encode()包装,直接将data.toJson(method)返回的Map对象传入data参数,Dio会自动完成表单编码,无需手动序列化。修正后的请求代码如下:Future<LoginModel> loginUser(LoginPost data, String method) async { try { final response = await _dio.post( 'api/users/v1/login/$method', // 直接传入Map,不要做jsonEncode处理 data: data.toJson(method), options: Options( headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': 'Basic ${base64Encode( utf8.encode('$clientId:$clientSecret'), )}', }, ), ); LoginModel model = LoginModel.fromJson(json.decode(response.data)); print(model.success); return model; } catch (error, stacktrace) { _printError(error, stacktrace); return LoginModel.withError(false, '', '$error', 0); } } - 若接口实际要求提交JSON格式数据:
将请求头中的Content-Type修改为application/json即可,此时既可以传入Map让Dio自动序列化,也可以保留手动json.encode的逻辑。
排查辅助手段
- 初始化Dio实例时添加内置的
LogInterceptor,打印实际发出的请求头、请求体、返回结果,和Postman中正常请求的参数做逐字段对比,可快速定位格式差异。 - 检查Dio实例的超时配置:若连接超时、接收超时设置时长过短,请求可能未等到响应就被截断,这类问题一般会进入catch回调,打印错误对象即可确认是否为超时异常。
内容的提问来源于stack exchange,提问作者Parama Artha
相关产品推荐
相关产品推荐

