可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I wonder if it's possible to directly send an array (not wrapped in a dictionary) in a POST request. Apparently the parameters
parameter should get a map of: [String: AnyObject]? But I want to be able to send the following example json:
[ "06786984572365", "06644857247565", "06649998782227" ]
回答1:
You can just encode the JSON with NSJSONSerialization
and then build the NSURLRequest
yourself. For example, in Swift 3:
var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let values = ["06786984572365", "06644857247565", "06649998782227"] request.httpBody = try! JSONSerialization.data(withJSONObject: values) Alamofire.request(request) .responseJSON { response in // do whatever you want here switch response.result { case .failure(let error): print(error) if let data = response.data, let responseString = String(data: data, encoding: .utf8) { print(responseString) } case .success(let responseObject): print(responseObject) } }
For Swift 2, see previous revision of this answer.
回答2:
For swift 3 and Alamofire 4 I use the following ParametersEncoding
and Array
extension:
import Foundation import Alamofire private let arrayParametersKey = "arrayParametersKey" /// Extenstion that allows an array be sent as a request parameters extension Array { /// Convert the receiver array to a `Parameters` object. func asParameters() -> Parameters { return [arrayParametersKey: self] } } /// Convert the parameters into a json array, and it is added as the request body. /// The array must be sent as parameters using its `asParameters` method. public struct ArrayEncoding: ParameterEncoding { /// The options for writing the parameters as JSON data. public let options: JSONSerialization.WritingOptions /// Creates a new instance of the encoding using the given options /// /// - parameter options: The options used to encode the json. Default is `[]` /// /// - returns: The new instance public init(options: JSONSerialization.WritingOptions = []) { self.options = options } public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { var urlRequest = try urlRequest.asURLRequest() guard let parameters = parameters, let array = parameters[arrayParametersKey] else { return urlRequest } do { let data = try JSONSerialization.data(withJSONObject: array, options: options) if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") } urlRequest.httpBody = data } catch { throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) } return urlRequest } }
Basically, it converts the array to a Dictionary
in order to be accepted as Parameters
argument, and then it takes back the array from the dictionary, convert it to JSON Data
and adds it as the request body.
Once you have it, you can create request this way:
let values = ["06786984572365", "06644857247565", "06649998782227"] Alamofire.request(url, method: .post, parameters: values.asParameters(), encoding: ArrayEncoding())
回答3:
Here is an example of encoding an Array of type Thing to JSON, using a router, and Ogra to do the JSON encoding:
import Foundation import Alamofire import Orga class Thing { ... } enum Router: URLRequestConvertible { static let baseURLString = "http://www.example.com" case UploadThings([Thing]) private var method: Alamofire.Method { switch self { case .UploadThings: return .POST } } private var path: String { switch self { case .UploadThings: return "upload/things" } } var URLRequest: NSMutableURLRequest { let r = NSMutableURLRequest(URL: NSURL(string: Router.baseURLString)!.URLByAppendingPathComponent(path)) r.HTTPMethod = method.rawValue switch self { case .UploadThings(let things): let custom: (URLRequestConvertible, [String:AnyObject]?) -> (NSMutableURLRequest, NSError?) = { (convertible, parameters) in var mutableRequest = convertible.URLRequest.copy() as! NSMutableURLRequest do { let jsonObject = things.encode().JSONObject() let data = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: NSJSONWritingOptions.PrettyPrinted) mutableRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") mutableRequest.HTTPBody = data return (mutableRequest, nil) } catch let error as NSError { return (mutableRequest, error) } } return ParameterEncoding.Custom(custom).encode(r, parameters: nil).0 default: return r } } }
回答4:
Swift 2.0
This code below post object array.This code is tested on swift 2.0
func POST(RequestURL: String,postData:[AnyObject]?,successHandler: (String) -> (),failureHandler: (String) -> ()) -> () { print("POST : \(RequestURL)") let request = NSMutableURLRequest(URL: NSURL(string:RequestURL)!) request.HTTPMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") var error: NSError? do { request.HTTPBody = try NSJSONSerialization.dataWithJSONObject(postData!, options:[]) } catch { print("JSON serialization failed: \(error)") } Alamofire.request(request) .responseString{ response in switch response.result { case .Success: print(response.response?.statusCode) print(response.description) if response.response?.statusCode == 200 { successHandler(response.result.value!) }else{ failureHandler("\(response.description)") } case .Failure(let error): failureHandler("\(error)") } } }
回答5:
@manueGE 's answer is right. I have a similar approach according to alamofire github's instruction: `
struct JSONDocumentArrayEncoding: ParameterEncoding { private let array: [Any] init(array:[Any]) { self.array = array } func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { var urlRequest = urlRequest.urlRequest let data = try JSONSerialization.data(withJSONObject: array, options: []) if urlRequest!.value(forHTTPHeaderField: "Content-Type") == nil { urlRequest!.setValue("application/json", forHTTPHeaderField: "Content-Type") } urlRequest!.httpBody = data return urlRequest! } }
` Then call this by customize a request instead of using the default one with parameter. Basically discard the parameter, since it is a dictionary.
let headers = getHeaders() var urlRequest = URLRequest(url: URL(string: (ServerURL + Api))!) urlRequest.httpMethod = "post" urlRequest.allHTTPHeaderFields = headers let jsonArrayencoding = JSONDocumentArrayEncoding(array: documents) let jsonAryEncodedRequest = try? jsonArrayencoding.encode(urlRequest, with: nil) request = customAlamofireManager.request(jsonAryEncodedRequest!) request?.validate{request, response, data in return .success } .responseJSON { /*[unowned self] */(response) -> Void in ... }
Also, the way to handle error in data is very helpful.
回答6:
There are 2 approach to send send JSON content as parameter.
You can send json as string and your web service will parse it on server.
d["completionDetail"] = "[{"YearOfCompletion":"14/03/2017","Completed":true}]"
You can pass each value within your json (YearOfCompletion
and Completed
) in form of sequential array. And your web service will insert that data in same sequence. Syntax for this will look a like
d["YearOfCompletion[0]"] = "1998" d["YearOfCompletion[1]"] = "1997" d["YearOfCompletion[2]"] = "1996" d["Completed[0]"] = "true" d["Completed[1]"] = "false" d["Completed[2]"] = "true"
I have been using following web service call function with dictionary, to trigger Alamofire
request Swift3.0.
func wsDataRequest(url:String, parameters:Dictionary) { debugPrint("Request:", url, parameters as NSDictionary, separator: "\n") //check for internete collection, if not availabale, don;t move forword if Rechability.connectedToNetwork() == false {SVProgressHUD.showError(withStatus: NSLocalizedString("No Network available! Please check your connection and try again later.", comment: "")); return} // self.request = Alamofire.request(url, method: .post, parameters: parameters) if let request = self.request as? DataRequest { request.responseString { response in var serializedData : Any? = nil var message = NSLocalizedString("Success!", comment: "")//MUST BE CHANGED TO RELEVANT RESPONSES //check content availability and produce serializable response if response.result.isSuccess == true { do { serializedData = try JSONSerialization.jsonObject(with: response.data!, options: JSONSerialization.ReadingOptions.allowFragments) //print(serializedData as! NSDictionary) //debugPrint(message, "Response Dictionary:", serializedData ?? "Data could not be serialized", separator: "\n") }catch{ message = NSLocalizedString("Webservice Response error!", comment: "") var string = String.init(data: response.data!, encoding: .utf8) as String! //TO check when html coms as prefix of JSON, this is hack mush be fixed on web end. do { if let index = string?.characters.index(of: "{") { if let s = string?.substring(from: index) { if let data = s.data(using: String.Encoding.utf8) { serializedData = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) debugPrint(message, "Courtesy SUME:", serializedData ?? "Data could not be serialized", separator: "\n") } } } }catch{debugPrint(message, error.localizedDescription, "Respone String:", string ?? "No respone value.", separator: "\n")} //let index: Int = text.distance(from: text.startIndex, to: range.lowerBound) debugPrint(message, error.localizedDescription, "Respone String:", string ?? "No respone value.", separator: "\n") } //call finised response in all cases self.delegate?.finished(succes: response.result.isSuccess, and: serializedData, message: message) }else{ if self.retryCounter
回答7:
I think based on Alamofire documentation you can write the code as following:
let values = ["06786984572365", "06644857247565", "06649998782227"] Alamofire.request(.POST, url, parameters: values, encoding:.JSON) .authenticate(user: userid, password: password) .responseJSON { (request, response, responseObject, error) in // do whatever you want here if responseObject == nil { println(error) } else { println(responseObject) } }