【问题标题】:How can we upload multipart form data with nested JSON parameters in Swift?我们如何在 Swift 中上传带有嵌套 JSON 参数的多部分表单数据?
【发布时间】:2015-11-12 07:23:24
【问题描述】:

我需要将图像上传到服务器端点,其结构必须如下:

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

我如何使用 NSURLSession(甚至可能是 Alamofire 或 AFNetworking)发送这样的请求?

【问题讨论】:

  • 你应该看看here它会帮助你。

标签: ios json swift nsurlsession alamofire


【解决方案1】:

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

对于寻求解决方案的其他人。

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]" 参数。

【讨论】:

  • 如果你打算使用 AFNetworking,我可能会建议 AFHTTPSessionManager 而不是 AFHTTPRequestOperationManager。前者使用NSURLSession,而后者使用NSURLConnection,在iOS 9 中已弃用。
  • 顺便说一句,您上面的答案不会像您在问题中要求的那样创建 JSON 请求。此解决方案创建x-www-form-urlencoded 请求(此处通过AFHTTPRequestSerializerrequestSerializer 的默认requestSerializer 实现),这样更好,因为它消除了对base64 编码的愚蠢需求。
  • @Rob:我没有意识到这一点。感谢您的见解。
【解决方案2】:

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

但如果你对图片进行 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()

如果你使用 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 请求,您可以在其中以illustrated here 发送二进制数据。

【讨论】:

  • 谢谢! @Rob 看来您的解决方案应该可以工作,但我已经找到了使用 AFNetworking 的更简单的实现(已发布答案)
  • @mohonish - 太好了。如果使用 Swift,我个人会使用 Alamofire(与 AFNetworking 的作者相同;不使用现在已弃用的 NSURLConnection,而 AFHTTPRequestOperationManager 使用;等等),但是 AFNetworking 和 Alamofire 都比编写自己的代码更容易NSURLSession 代码。
【解决方案3】:

试试这个:

    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)

【讨论】:

  • Rob :我仍在使用 8.4,但我不知道这在 iOS 9 中已被弃用。感谢告知。
猜你喜欢
  • 2019-08-17
  • 2016-02-29
  • 2015-09-30
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 2013-08-24
  • 2023-03-23
  • 1970-01-01
相关资源
最近更新 更多