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

Flutter发送JSON Array格式POST请求的实现与报错排查

问题修复方案

你当前遇到的报错分为两类,分别是SSL证书校验失败、请求格式不符合接口要求,对应解决方法如下:


1. 修复HandshakeException证书报错

报错核心原因是目标服务端的SSL证书已过期,Flutter内置的网络请求客户端默认会严格校验SSL证书有效性,而Postman默认开启了忽略证书无效的配置,因此可以正常发起请求。

注意:测试阶段可临时绕过证书校验快速调试,生产环境必须要求服务端更换有效SSL证书,长期绕过校验存在中间人攻击的安全风险。

临时绕过证书校验的实现:不要直接使用http包默认的客户端,自定义基于dart:ioHttpClient的请求客户端,配置证书校验回调:

import 'dart:io';
import 'package:http/io_client.dart';

// 构造测试用忽略证书校验的客户端
HttpClient _httpClient = HttpClient()
  ..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
final httpClient = IOClient(_httpClient);

2. 修复POST请求体格式错误

你当前代码有四个格式问题:

  • 接口要求请求体最外层是JSON数组(最外层包裹[]),你直接传入了单个JSON对象(最外层是{}),不符合接口格式要求
  • 请求头的键名写错:Content type 应为标准头字段 Content-Type,否则服务端无法正确识别JSON请求体
  • merchantKey字符串拼接错误:原字符串的$符号被Dart识别为字符串插值语法,导致值和接口要求的不一致,需要用raw字符串(前缀加r)避免转义
  • 手动拼接items字段的JSON字符串容易出现转义错误,直接通过jsonEncode序列化商品列表得到字符串即可。

核心请求体修正逻辑:将模型对象放入数组后再进行JSON编码,即:

// 错误写法:直接编码单个对象,最外层是{}
// body: convert.jsonEncode(siPayModel.toJson())
// 正确写法:放入数组后编码,最外层是[]
body: convert.jsonEncode([siPayModel.toJson()])

3. 修正后的完整请求代码

import 'dart:convert' as convert;
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';

import '../model/sipayjson.dart';

class SiPay {
  static const testUrl = "https://provisioning.sipay.com.tr/ccpayment/api/paySmart2D";
  static const liveUrl = "https://app.sipay.com.tr/ccpayment/api/paySmart2D";
  static const sKey = "b46a67571aa1e7ef566f1712a";
  static const pKey = "6d4a7e9374a7315b0b9";
  // 用r前缀声明raw字符串,避免$被识别为插值语法
  static const merchantKey = r"$2y$10$HmRgYosneqcwHj.UH7upGuyCZqpQ1ITgSMj9Vvxn.t6f.Vdf2SQFO";

  // 修正请求头键名
  Map<String, String> header = {
    "Content-Type": "application/json",
    "Authorization": "Bearer",
    "Accept": "application/json",
  };

  // 构造测试用客户端,临时忽略证书校验
  final http.Client _client = IOClient(
    HttpClient()..badCertificateCallback = (cert, host, port) => true
  );

  Future<void> doPayment() async {
    // 构造商品列表,直接序列化得到JSON字符串,避免手动转义出错
    final itemsList = [
      {"name":"pr001","price":"2.30","quantity":1,"description":"pr001"},
      {"name":"pr001","price":"2.70","quantity":1,"description":"pr001"},
      {"name":"pr001","price":"5.00","quantity":2,"description":"pr001"}
    ];
    final itemsStr = convert.jsonEncode(itemsList);

    SiPayModel siPayModel = SiPayModel(
      ccHolderName: "John Dao",
      ccNo: "4508034508034509",
      expiryMonth: 12,
      expiryYear: 2026,
      cvv: 543,
      currencyCode: "TRY",
      installmentsNumber: 1,
      invoiceId: 5874544,
      invoiceDescription: "5974544 Ödemesi",
      name: "John",
      surname: "Dao",
      total: 458,
      merchantKey: merchantKey,
      items: itemsStr,
      cancelUrl: "string",
      returnUrl: "string",
      hashKey: "", // 后续按照接口签名规则计算出正确值替换即可
      orderType: 0
    );

    var res = await _client.post(
      Uri.parse(testUrl),
      headers: header,
      // 核心:将模型对象放入数组后再编码,匹配接口要求的数组格式
      body: convert.jsonEncode([siPayModel.toJson()])
    );

    if (res.statusCode == 200) {
      print(res.statusCode);
      print(res.body);
    } else {
      print(res.statusCode);
      throw Exception("Payment error");
    }
  }
}

补充说明

如果请求格式正确后仍返回101 Unauthorized错误,是因为你还未按照接口文档的签名规则生成合法的hash_key值,该问题属于接口鉴权逻辑范畴,和Flutter请求实现无关,按照文档要求计算出对应签名值传入即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:27:14