我们如何在 Swift 中上传带有嵌套 JSON 参数的多部分表单数据?
How can we upload multipart form data with nested JSON parameters in Swift?
我需要将图像上传到结构必须如下所示的服务器端点:
{ "image": { "file": imageData }, "access_token": access_token }
如何使用 NSURLSession(或者甚至是 Alamofire 或 AFNetworking)发送这样的请求?
试试这个:
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)
您不能只在 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)
}
}
但以上两者都对响应的性质做出了假设,即服务器正在对来自 JSON 的图像数据进行 base64 解码,等等,但希望这能说明基本模式。
或者,使用 application/x-www-form-urlencoded
请求,您可以在其中发送二进制数据 illustrated here。
在
的帮助下找到了使用 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]"
参数。
我需要将图像上传到结构必须如下所示的服务器端点:
{ "image": { "file": imageData }, "access_token": access_token }
如何使用 NSURLSession(或者甚至是 Alamofire 或 AFNetworking)发送这样的请求?
试试这个:
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)
您不能只在 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)
}
}
但以上两者都对响应的性质做出了假设,即服务器正在对来自 JSON 的图像数据进行 base64 解码,等等,但希望这能说明基本模式。
或者,使用 application/x-www-form-urlencoded
请求,您可以在其中发送二进制数据 illustrated here。
在
的帮助下找到了使用 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]"
参数。