You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter应用集成Payfast API时的HTTP请求错误排查求助

解决Flutter集成Payfast支付网关的404/500错误问题

嘿,我看了你这段集成Payfast的Flutter代码,发现几个关键问题导致你拿不到正确响应甚至触发404/500错误,咱们一步步拆解修复:

核心问题分析

  • 请求格式不匹配:Payfast的/eng/process端点只接受application/x-www-form-urlencoded的表单数据,你却用了JSON格式发送请求,这直接会导致服务器返回500错误。
  • 签名生成逻辑错误:你的签名字符串里重复了merchant_id,还混入了不该有的Content-Type参数,而且timestamp格式不符合Payfast要求,这会导致签名验证失败。
  • 请求头滥用:Payfast不需要把merchant-idtimestamp这些参数放在请求头里,所有业务参数都应该放在表单请求体中。
  • 响应处理错误/eng/process返回的是HTML结账页面,你直接把字符串传给自定义页面是无法正常跳转的,得用WebView加载。

修正后的完整代码

import 'dart:convert';
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

// 假设这是你的支付触发方法
Future<void> initiatePayfastPayment(BuildContext context) async {
  // 生成符合Payfast要求的timestamp格式:YYYY-MM-DD HH:MM:SS
  DateTime now = DateTime.now();
  String timestamp = "${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')} ${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}";

  // 构建所有请求参数(注意不要包含signature)
  Map<String, String> params = {
    'merchant_id': '10000100',
    'merchant_key': '46f0cd694581a',
    'amount': '100.00',
    'item_name': '#000001',
    'timestamp': timestamp,
    'version': 'v1',
    // 如果你的账号设置了passphrase,需要加上这一行
    // 'passphrase': 'your_sandbox_passphrase',
  };

  // 按字母顺序排序参数(Payfast签名要求必须排序)
  List<String> sortedKeys = params.keys.toList()..sort();
  String signatureString = sortedKeys.map((key) => "$key=${params[key]}").join('&');

  // 如果有passphrase,需要在签名字符串末尾拼接(注意:passphrase不需要参与排序)
  // signatureString += "&passphrase=${params['passphrase']}";

  // 生成MD5签名
  String signature = md5.convert(utf8.encode(signatureString)).toString();
  params['signature'] = signature;

  // 发起POST请求
  HttpClient httpClient = HttpClient();
  HttpClientRequest request = await httpClient.postUrl(Uri.https("sandbox.payfast.co.za", "/eng/process"));

  // 设置正确的Content-Type
  request.headers.set('Content-Type', 'application/x-www-form-urlencoded');

  // 将参数转换为表单编码格式
  String formBody = params.entries.map((entry) => "${Uri.encodeComponent(entry.key)}=${Uri.encodeComponent(entry.value)}").join('&');
  request.add(utf8.encode(formBody));

  // 获取响应
  HttpClientResponse response = await request.close();
  print("响应状态码: ${response.statusCode}");
  
  String checkoutHtml = await response.transform(utf8.decoder).join();
  httpClient.close();

  print("Payfast响应内容: $checkoutHtml");

  // 用WebView加载结账页面(需要先添加webview_flutter依赖)
  if (context.mounted) {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => Scaffold(
          appBar: AppBar(title: const Text("Payfast结账")),
          body: WebViewWidget(
            controller: WebViewController()
              ..loadHtmlString(checkoutHtml)
              ..setJavaScriptMode(JavaScriptMode.unrestricted),
          ),
        ),
      ),
    );
  }
}

额外注意事项

  1. 确保你的Payfast沙箱账号是已激活状态,merchant_idmerchant_key是正确的沙箱凭据(不要用生产环境的凭据)。
  2. 如果你的账号设置了passphrase,必须在参数中添加并参与签名生成,否则签名验证会失败。
  3. Payfast的/eng/process端点返回的是完整的结账HTML页面,必须用WebView组件加载才能让用户完成支付流程,直接传递字符串到自定义页面是无效的。
  4. 测试时确保你的设备能正常访问Payfast沙箱环境(不要有网络代理或防火墙限制)。

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

火山引擎 最新活动