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

Flutter中使用Dio.post调用支付接口返回<!DOCTYPE html>而非JSON的问题求助

问题排查与解决方案

我来帮你梳理这个问题——Postman调用正常但Flutter返回HTML,而且支付实际成功了,这大概率是请求格式或重定向处理的问题,咱们一步步拆解:

1. 最可能的原因:手动设置Content-Type导致格式冲突

你在postData方法里硬编码了Content-Type: application/json,但实际发送的是带文件的FormData。Dio本来会自动为FormData生成正确的multipart/form-data请求头(包含boundary分隔符),但你的手动覆盖会让服务器无法正确解析请求,最终返回HTML格式的错误页面。

解决办法:

删除手动设置的Content-Type,让Dio自动适配请求格式:

static Future<Response> postData({
  required String endPoint,
  required dynamic data,
  String? token,
}) async {
  // 只保留Authorization头,去掉Content-Type
  _dio.options.headers = {
    'Authorization': 'Bearer $token',
  };
  return await _dio.post(endPoint, data: data);
}

如果你的接口需要同时支持JSON和FormData请求,可以动态设置头:

static Future<Response> postData({
  required String endPoint,
  required dynamic data,
  String? token,
}) async {
  final headers = <String, String>{};
  if (token != null) {
    headers['Authorization'] = 'Bearer $token';
  }
  // 只有非FormData请求才设置JSON类型
  if (data is! FormData) {
    headers['Content-Type'] = 'application/json';
  }
  _dio.options.headers = headers;
  return await _dio.post(endPoint, data: data);
}

2. 重定向未处理导致拿到HTML跳转页

支付接口可能在成功后触发重定向(比如跳转到支付结果页面),Postman会自动跟随重定向并返回最终的JSON,但你在Dio初始化时设置了followRedirects: false,这会让Dio直接返回重定向响应(状态码3xx),而响应内容通常是HTML格式的跳转页面。

解决办法:

  • 方案1:允许自动跟随重定向
    修改Dio初始化的BaseOptions:
static init() {
  _dio = Dio(
    BaseOptions(
      baseUrl: baseUrl,
      receiveDataWhenStatusError: true,
      followRedirects: true, // 改为true
      validateStatus: (status) {
        return status! < 500;
      },
      connectTimeout: 60 * 1000 ,
      receiveTimeout: 60 * 1000 ,
    ),
  );
}
  • 方案2:手动处理重定向
    如果需要自定义重定向逻辑,可以在请求后判断状态码并提取跳转地址:
await DioHelper.postData(
  endPoint: '$paymentEndPoint/$subWalletID',
  token: payToken,
  data: _data,
).then((value) {
  if (value.statusCode >= 300 && value.statusCode < 400) {
    // 提取重定向地址并发起新请求
    final redirectUrl = value.headers['location']?.first;
    if (redirectUrl != null) {
      final finalResponse = await DioHelper._dio.get(redirectUrl);
      print('最终支付响应:${finalResponse.data}');
    }
  } else {
    print('Pay done response ${value.data}');
  }
});

3. 验证请求端点与参数的一致性

虽然支付成功了,但还是要确认:

  • $paymentEndPoint/$subWalletID是否存在多余斜杠(比如paymentEndPoint结尾已有/,拼接后变成//xxx)
  • FormData的参数名称是否和Postman完全一致(比如image、amount等字段拼写)
  • 传入的payToken是否和Postman使用的有效token一致

4. 打印完整响应信息定位问题

可以打印响应的状态码、头信息和完整内容,看看HTML里的具体错误提示:

await DioHelper.postData(...).then((value) {
  if (kDebugMode) {
    print('状态码:${value.statusCode}');
    print('响应头:${value.headers}');
    print('响应内容:${value.data}');
  }
}).catchError((error) {
  if (kDebugMode) {
    print('请求错误:${error.toString()}');
  }
});

比如HTML里如果显示400 Bad Request,说明请求格式错误;如果是302 Found,就是重定向问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 14:22:30