【问题标题】:Sending json array via Alamofire通过 Alamofire 发送 json 数组
【发布时间】:2015-01-17 13:34:39
【问题描述】:

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

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

【问题讨论】:

    标签: swift alamofire


    【解决方案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】:
      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
                                }
                            }
                        }
    

    【讨论】:

      【解决方案3】:
      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 数组的操作

      【讨论】:

        【解决方案4】:

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

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

           d["completionDetail"] = "[{"YearOfCompletion":"14/03/2017","Completed":true}]"
          
        2. 您可以以顺序数组的形式传递 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")
                                        }
                                    }
                                }
                            }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 < 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
                    }
                }
            }
        }
        

        【讨论】:

          【解决方案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?.validate{request, response, data in
                  return .success
                  }
                  .responseJSON { /*[unowned self] */(response) -> Void in
                      ...
              }
          

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

          【讨论】:

            【解决方案6】:

            对于 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:
            • 谢谢你,你救了我!!
            【解决方案7】:

            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”
            【解决方案8】:

            这是一个将 Thing 类型的 Array 编码为 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
                    }
                }
            }
            

            【讨论】:

              【解决方案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]?。您不能将其传递给数组。它必须是一本字典。因此问题。
              • 如果您传递的是字典对象而不是数组,那么这个答案将是正确的。编码参数将处理其余部分。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-01-09
              • 2016-05-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多