How can we upload multipart form data with nested JSON parameters in Swift?

别来无恙 提交于 2019-12-21 06:27:13

问题


I need to upload an image to the server endpoint where the structure has to be as following:

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

How can I send such a request using NSURLSession (or maybe even Alamofire or AFNetworking)?


回答1:


You cannot just include binary image data in a JSON request. JSON requires text representation, so if you do this, you must convert it to string (e.g. base64 encoding), use that in the JSON, and then the server code would presumably convert the base64 string back to binary data before attempting to use it.

But if you were base64 encoding of the image, it might look something like:

// 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, e.g. 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()

If you use Alamofire, this is simplified:

// 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)
        }
    }

But both of the above are making assumptions about the nature of the response, that the server is base64 decoding the image data from the JSON, etc., but hopefully this illustrates the basic patterns.

Alternatively, use an application/x-www-form-urlencoded request, in which you can send binary data as illustrated here.




回答2:


Found a solution using AFNetworking with help from https://stackoverflow.com/a/11092052/3871476

For others looking for the solution.

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)
})

The trick was to use the "image[file]" parameter.




回答3:


Try this:

    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)


来源:https://stackoverflow.com/questions/32087960/how-can-we-upload-multipart-form-data-with-nested-json-parameters-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!