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

时间:2021-11-10 00:42:10

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

如何使用NSURLSession(或者甚至是Alamofire或AFNetworking)发送此类请求?

3 个解决方案

#1


4  

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.

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

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

但是如果你是图像的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, 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:

如果您使用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)
        }
    }

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.

但是上面两个都假设了响应的性质,服务器是基于64解码来自JSON的图像数据等,但希望这说明了基本模式。

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

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

#2


0  

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)

#3


0  

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

在https://*.com/a/11092052/3871476的帮助下使用AFNetworking找到了解决方案

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.

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

#1


4  

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.

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

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

但是如果你是图像的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, 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:

如果您使用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)
        }
    }

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.

但是上面两个都假设了响应的性质,服务器是基于64解码来自JSON的图像数据等,但希望这说明了基本模式。

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

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

#2


0  

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)

#3


0  

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

在https://*.com/a/11092052/3871476的帮助下使用AFNetworking找到了解决方案

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.

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