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

POST请求form-data传递异常:Postman正常但代码报hash无效

问题根源

你当前代码把参数拼成了application/x-www-form-urlencoded格式(用&分隔键值对),但接口要求的是multipart/form-data格式——这两种POST请求的参数编码逻辑完全不同,哪怕hash值本身正确,服务端因为接收参数的方式不匹配,也会判定hash无效。

正确实现multipart/form-data请求的方案

下面是能生成符合要求的form-data请求的Swift代码:

首先实现一个生成form-data格式数据的工具方法:

func createMultipartFormData(from parameters: [String: Any]) -> (data: Data, contentType: String)? {
    let boundary = UUID().uuidString
    var body = Data()
    
    for (key, value) in parameters {
        // 添加字段分隔边界
        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        // 写入字段描述头
        body.append("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".data(using: .utf8)!)
        // 写入字段值:如果是JSON对象就序列化,否则直接转字符串
        if let jsonValue = value as? [String: Any] {
            do {
                let jsonData = try JSONSerialization.data(withJSONObject: jsonValue)
                body.append(jsonData)
            } catch {
                print("JSON序列化失败: \(error)")
                return nil
            }
        } else {
            body.append("\(value)\r\n".data(using: .utf8)!)
        }
    }
    
    // 添加结束边界
    body.append("--\(boundary)--\r\n".data(using: .utf8)!)
    
    let contentType = "multipart/form-data; boundary=\(boundary)"
    return (body, contentType)
}

然后修改你的请求方法:

func request() {
    let dict: [String: Any] = [
        "hash": "fd399b06f23440bc0ff6f040800941f0",
        "term_url_3ds": "https://xxx-xxx.xx.xx/xx/xxxx/xxx",
        "order_id": "e9930dea-0340-4fe8-394b-a35fa3f915c2",
        "payment_token": ["xxx": "xxx"], // 直接传字典,内部自动转JSON
        "order_currency": "USD",
        "order_amount": "1.00",
        "action": "APPLEPAY",
        "order_description": "PAYMENT",
        "payer_ip": "192.168.1.101",
        "client_key": "8UYSDVUVS8J",
        "payer_email": "XXX@gmail.com",
        "payer_phone": "+14058370914"
    ]
    
    guard let formData = createMultipartFormData(from: dict) else {
        print("生成form-data失败")
        return
    }
    
    guard let mainUrl = URL(string: "https://xxx.xxx.com/post/") else {
        return
    }
    
    var request = URLRequest(url: mainUrl)
    request.httpMethod = "POST"
    request.httpBody = formData.data
    // 必须设置带boundary的Content-Type,服务端才能正确解析
    request.setValue(formData.contentType, forHTTPHeaderField: "Content-Type")
    
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        if let httpResponse = response as? HTTPURLResponse {
            print("响应状态码: \(httpResponse.statusCode)")
        }
        
        if let error = error {
            debugPrint("请求错误: \(error.localizedDescription)")
            return
        }
        
        guard let data = data else {
            print("无响应数据")
            return
        }
        
        if let responseStr = String(decoding: data, as: UTF8.self) {
            print("响应内容: \(responseStr)")
        }
        
        let jsonDecoder = JSONDecoder()
        do {
            let response = try jsonDecoder.decode(MyResponse.self, from: data)
            print("解析后的响应: \(response)")
        } catch {
            print("JSON解析失败: \(error)")
        }
    }
    task.resume()
}
关键注意点
  • multipart/form-data必须用**边界符(boundary)**分隔每个字段,每个字段都要有对应的描述头,和你之前用&拼接键值对的逻辑完全不同。
  • 像payment_token这种JSON类型的参数,直接传字典让代码内部序列化,避免手动拼字符串导致的编码错误。
  • 一定要设置带boundary的Content-Type头部,这是服务端识别form-data格式的关键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 10:12:52