如何在multipart/form-data请求中传递JSON数组类型参数
multipart/form-data请求传递多元素package_json参数实现方案
问题描述
需要在Content-Type为multipart/form-data的请求中传递参数,单值场景下package_json参数可以正常传递,但传递包含多个对象的JSON数组格式package_json时失败。
现有封装的网络请求方法仅支持[String: String]类型的普通文本参数,以及Data类型的图片参数,单值场景的参数写法如下:
let param = [ "outletId : "1", "vehicleId" : "1", "instructions" : tvInstructions.text, "package_json" : "[{\"packageId\":\"1\"}]", "addressId" : "1" ]
当前使用的上传请求封装代码:
func postrequest(_ request: String, onPath imagesData:[Data]?,_ imageName : String, andParameter parameters: [String:String]?, withCompletion response: @escaping serviceCompletion) { let headers: HTTPHeaders headers = ["Content-type": "multipart/form-data"] AF.upload(multipartFormData: { multiPart in if let allParams = parameters { for (key, value) in allParams { multiPart.append(value.data(using: .utf8)!, withName: key) } } for imageData in imagesData ?? [] { multiPart.append(imageData, withName: "\(imageName)", fileName: "file.jpg", mimeType: "image/jpg") } }, to: request, usingThreshold: UInt64.init(), method: .post, headers: headers).response { (res) in if((res.error == nil)){ do { response(res.data,res.error) } } else{ response(res.data,res.error) } } }
需要传递的多元素package_json格式为:[{"packageId": 1}, {"packageId": 2}, {"packageId": 3}],尝试修改方法支持[String: Any]类型参数未成功。
调用封装方法的示例代码:
func sendData() { let param = [ "outletId" : "1", "vehicleId" : "1", "instructions" : tvInstructions.text, "package_json" : "[{\"packageId\":\"1\"}]", "addressId" : "1" ] ApiNetworkManager.shared.postrequest(Api.completeUrl, onPath: [], "", andParameter: param) { (response, err) in ApiNetworkManager.shared.hideHud() debugPrint(param) let json = JSON.init(response!) debugPrint(json) if err == nil { if err == nil && response != nil { if json.dictionaryValue["success"]?.stringValue == "1" { // 业务逻辑 } else{ let message = json.dictionaryValue["message"]?.stringValue self.showAlert(Message: message ?? "Error") } } else { print(err?.localizedDescription as Any) let message = json.dictionaryValue["message"]?.stringValue self.showAlert(Message: message ?? "Error") } } else{ ApiNetworkManager.shared.hideHud() let message = err?.localizedDescription self.showAlert(Message: message ?? "Error") } } }
解决方案
不需要修改现有网络封装的参数类型,直接把多元素的JSON数组序列化成合法的JSON字符串,作为package_json的value传入即可,和单值场景的传参逻辑完全一致。
具体实现步骤
- 先构造需要传递的
package_json原生数组对象
// 多包裹数据数组 let packageList = [ ["packageId": "1"], ["packageId": "2"], ["packageId": "3"] ]
- 用系统
JSONSerialization把数组序列化为JSON字符串,注意处理转义问题
var packageJsonStr = "" if let jsonData = try? JSONSerialization.data(withJSONObject: packageList, options: []), let jsonStr = String(data: jsonData, encoding: .utf8) { packageJsonStr = jsonStr }
- 把生成的JSON字符串直接放入参数字典即可,不需要改动现有网络封装
let param = [ "outletId" : "1", "vehicleId" : "1", "instructions" : tvInstructions.text ?? "", "package_json" : packageJsonStr, "addressId" : "1" ]
注意事项
- 不要手动拼接JSON字符串,容易出现转义错误、格式非法的问题,必须通过序列化方法生成合法JSON字符串
- 确认后端要求的
packageId字段类型是字符串还是数字,如果要求数字类型,构造数组时直接传整型值即可,序列化后会自动生成不带引号的数字格式 - 现有封装逻辑里是把参数值转成
utf8编码的Data追加到multipart表单,JSON字符串本身就是纯文本,完全兼容现有逻辑,不需要修改封装层代码
内容的提问来源于stack exchange,提问作者Mel
相关产品推荐
相关产品推荐

