我们如何在Swift中嵌套JSON参数上传多部分表单数据?

我需要上传一个图像到结构必须如下的服务器端点:

{ "image": { "file": imageData }, "access_token": access_token } 

我怎样才能发送这样的请求使用NSURLSession(或者甚至Alamofire或AFNetworking)?

您不能只包含二进制图像数据在JSON请求。 JSON需要文本表示,所以如果你这样做,你必须将其转换为string(例如base64编码),在JSON中使用它,然后在尝试使用它之前,服务器代码可能会将base64string转换回二进制数据。

但是,如果你是图像的base64编码,它可能看起来像这样:

 // get image data let imageData = UIImagePNGRepresentation(image) // convert to base64 let base64String = imageData.base64EncodedStringWithOptions(nil) // build parameters let parameters = ["image": ["file" : base64String], "access_token" : accessToken] // get JSON var error: NSError? let data = NSJSONSerialization.dataWithJSONObject(parameters, options: nil, error: &error) assert(data != nil, "Unable to serialize \(error)") // build request let url = NSURL(string: "http://example.com/upload")! let request = NSMutableURLRequest(URL: url) request.addValue("text/json", forHTTPHeaderField: "Content-Type") request.HTTPMethod = "POST" let task = NSURLSession.sharedSession().uploadTaskWithRequest(request, fromData: data) { data, response, error in // check for basic connectivity errors if error != nil { println("error: \(error)") return } // check for server errors if let httpResponse = response as? NSHTTPURLResponse, let statusCode = httpResponse.statusCode as Int? { if statusCode != 200 { println("status code is \(statusCode)") } } // check for details of app-level server response, eg if JSON that was dictionary: var parseError: NSError? if let responseObject = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &parseError) as? [String : AnyObject] { println(responseObject) } else { println("JSON parse failed: \(parseError)") println("response was: \(response)") let responseString = NSString(data: data, encoding: NSUTF8StringEncoding) println("responseString was: \(responseString)") } } task.resume() 

如果你使用Alamofire,这是简化的:

 // build parameters let parameters = ["image": ["file" : base64String], "access_token" : accessToken] as [String : AnyObject] // build request let urlString = "http://example.com/upload" Alamofire.request(.POST, urlString, parameters: parameters, encoding: .JSON) .responseJSON(options: nil) { request, response, responseObject, error in if error != nil { println(error) } else { println(responseObject) } } 

但是,上面都是对响应性质做出假设,服务器是base64解码来自JSON等的图像数据,但是希望这可以说明基本模式。

或者,使用application/x-www-form-urlencoded请求,您可以在其中发送二进制数据, 如图所示 。

尝试这个:

  var request = NSMutableURLRequest(URL: NSURL(string: "https://\(IP):\(port)/")!) var response: NSURLResponse? var error: NSError? //Adding the JSON String in HTTP Body request.HTTPBody = NSJSONSerialization.dataWithJSONObject(jsonString, options: nil, error: &error) request.timeoutInterval = (number as! NSTimeInterval) request.HTTPMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("gzip", forHTTPHeaderField: "Accept-encoding") let urlData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error) 

使用AFNetworking在https://stackoverflow.com/a/11092052/3871476的帮助下find了一个解决scheme

对于其他寻找解决scheme。

 let manager = AFHTTPRequestOperationManager(baseURL: NSURL(string: url)) let request = manager.POST(url, parameters: param, constructingBodyWithBlock: {(formData: AFMultipartFormData!) -> Void in formData.appendPartWithFileData(imgdata, name: "image[file]", fileName: "photo.jpeg", mimeType: "image/jpeg") }, success: {(operation: AFHTTPRequestOperation!, responseObject: AnyObject!) -> Void in //Success }, failure: {(operation: AFHTTPRequestOperation!, error: NSError!) -> Void in //Failure println(error.localizedDescription) }) 

诀窍是使用"image[file]"参数。