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
相关产品推荐
相关产品推荐

