通过 Alamofire 发送 json 数组

Posted

技术标签:

【中文标题】通过 Alamofire 发送 json 数组【英文标题】:Sending json array via Alamofire 【发布时间】:2014-11-19 21:02:33 【问题描述】:

我想知道是否可以在 POST 请求中直接发送一个数组(不包含在字典中)。显然parameters 参数应该得到一个映射:[String: AnyObject]? 但我希望能够发送以下示例 json:

[
    "06786984572365",
    "06644857247565",
    "06649998782227"
]

【问题讨论】:

【参考方案1】:

您可以使用 NSJSONSerialization 对 JSON 进行编码,然后自己构建 NSURLRequest。例如,在 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)

AF.request(request)                               // Or `Alamofire.request(request)` in prior versions of Alamofire
    .responseJSON  response in
        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)
        

对于 Swift 2,请参阅此答案的 previous revision。

【讨论】:

@Rob 我收到类似 Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0" 之类的错误。 UserInfo=NSDebugDescription=字符 0 周围的值无效。 有什么想法吗? @NikunjJadav 响应不是 JSON。您可能想查看response.data(请参阅上面的修订答案)以查看 Web 服务返回的确切内容。通常会有关于问题性质的叙述性描述。 @Rob 很好的答案非常感谢你,但在我的情况下,如果方法是 .get 而不是 .post 怎么办? 对于GET 请求,x-www-form-urlencoded 键值对中没有提供正文和参数。最合乎逻辑的解决方案是提供一个键值对,其中值是一个数组:AF.request("https://robertmryan.com/privatetest/form/results.php", method: .get, parameters: ["stooges": ["moe", "larry", "curly"]])。您将使用键检索名称数组,例如$_GET['stooges']$_REQUEST['stooges']. @famfamfam - 我刚刚测试过它,它工作正常。我建议您确认您的服务器确实需要一个 JSON 对象,它只是一个数组。 (这将是一种非常不寻常的模式,几乎闻所未闻。)如果它不适合你,你的问题就出在其他地方。【参考方案2】:

对于 swift 3 和 Alamofire 4,我使用以下 ParametersEncodingArray 扩展:

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
    

基本上,它将数组转换为 Dictionary 以便被接受为 Parameters 参数,然后从字典中取回数组,将其转换为 JSON Data 并将其添加为请求正文.

一旦你有了它,你可以通过这种方式创建请求:

let values = ["06786984572365", "06644857247565", "06649998782227"]
Alamofire.request(url,
                  method: .post,
                  parameters: values.asParameters(),
                  encoding: ArrayEncoding())

【讨论】:

像魅力一样工作! :+1: 谢谢你,你救了我!!【参考方案3】:

这是一个将 Thing 类型的数组编码为 JSON 的示例,使用路由器和 Ogra 进行 JSON 编码:

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 此代码在 post 对象数组下方。此代码在 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)")
                
        

    

【讨论】:

调用方法时出错。 POST(baseUrl+WS_LOGIN, postData: jsonObject as a, successHandler: ()#>, failureHandler: ()#>) 我应该用什么在处理程序中 参数类型“NSMutableURLRequest”不符合预期类型“URLRequestConvertible”【参考方案5】:

@manueGE 的回答是正确的。根据 alamofire github 的说明,我有类似的方法: `

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!
    

` 然后通过自定义请求而不是使用带参数的默认请求来调用它。基本上丢弃参数,因为它是一个字典。

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?.validaterequest, response, data in
        return .success
        
        .responseJSON  /*[unowned self] */(response) -> Void in
            ...
    

另外,处理数据错误的方法也很有帮助。

【讨论】:

【参考方案6】:
let url = try Router.baseURL.asURL()

// Make Request
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
urlRequest.httpMethod = "post"

// let dictArray: [[String: Any]] = []
urlRequest = try! JSONEncoding.default.encode(urlRequest, withJSONObject: dictArray)

我在项目中上传 JSON 数组的操作

【讨论】:

【参考方案7】:
  func placeOrderApi(getUserId:String,getDateId:String,getTimeID:String,getAddressId:String,getCoupon:String)
            
                let data = try! JSONSerialization.data(withJSONObject: self.arrOfServices, options: [])
                let jsonBatch : String = String(data: data, encoding: .utf8)!
                
                //try! JSONSerialization.data(withJSONObject: values)
               let params = [
                   "user_id":getUserId,
                   "time_id":getTimeID,
                   "date_id":getDateId,
                   "address_id":getAddressId,
                   "services":jsonBatch,
                   "payment_mode":paymentVia,
                   "coupon":getCoupon
                ] as [String : Any]
               
               print(params)
               self.objHudShow()
                
                Alamofire.request(BaseViewController.API_URL + "place_order", method: .post, parameters: params, encoding: JSONEncoding.default)
                    .responseJSON  response in
                        debugPrint(response)
               
                    
                    switch response.result 
                        
                    case .success (let data):
                        print(data)
                                
                    self.objHudHide()
                    if response.result.value != nil
                    
                       
                        let json : JSON = JSON(response.result.value!)
                       
                         if json["status"] == true
                         
                           
                         
                          else
                         
                            self.view.makeToast(NSLocalizedString(json["msg"].string ?? "", comment: ""), duration: 3.0, position: .bottom)
                          
                     
                             
                    
                               
                        break
                                
                    case .failure:
                               self.objHudHide()
                               
                               print("Error in upload:)")
                                break
                            
                        
                    

【讨论】:

【参考方案8】:

有两种方法可以发送 JSON 内容作为参数。

    您可以将 json 作为字符串发送,您的 Web 服务将在服务器上对其进行解析。

     d["completionDetail"] = "["YearOfCompletion":"14/03/2017","Completed":true]"
    

    您可以以顺序数组的形式传递 json 中的每个值(YearOfCompletionCompleted)。您的 Web 服务将以相同的顺序插入该数据。这个语法看起来像

    d["YearOfCompletion[0]"] = "1998"  
    d["YearOfCompletion[1]"] = "1997"  
    d["YearOfCompletion[2]"] = "1996"  
    
    d["Completed[0]"] = "true"  
    d["Completed[1]"] = "false"  
    d["Completed[2]"] = "true"  
    

我一直在使用以下带有字典的 Web 服务调用函数来触发 Alamofire 请求 Swift3.0

func wsDataRequest(url:String, parameters:Dictionary<String, Any>) 
    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")
                                
                            
                        
                    catchdebugPrint(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 < 1 //this happens really frequntly so in that case this fn being called again as a retry
                    self.wsDataRequest(url: url, parameters: parameters)
                else
                    message = response.error?.localizedDescription ?? (NSLocalizedString("No network", comment: "")+"!")
                    SVProgressHUD.showError(withStatus: message);//this will show errror and hide Hud
                    debugPrint(message)

                    //call finised response in all cases
                    self.delay(2.0, closure: self.delegate?.finished(succes: response.result.isSuccess, and: serializedData, message:message))
                
                self.retryCounter += 1
            
        
    

【讨论】:

【参考方案9】:

我认为根据 Alamofire 文档,您可以编写如下代码:

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)
        

【讨论】:

不,parameters[String: AnyObject]?。您不能将其传递给数组。它必须是一本字典。因此问题。 如果您传递的是字典对象而不是数组,那么这个答案将是正确的。编码参数将处理其余部分。

以上是关于通过 Alamofire 发送 json 数组的主要内容,如果未能解决你的问题,请参考以下文章

发送包含数组的数组 json 主体(Alamofire、Swift、iOS)

发送 Alamofire JSON 数组 Swift

Alamofire:发送带有字典数组的 JSON

试图在 alamofire 中发送 json 对象,但它在 json 数组中

在 swift 中使用 alamofire 发送 JSON 数组作为参数

如何在 swift 3 中使用 Alamofire 制作和发送字典数组(JSON 格式)发送到服务器