Swift - отправить NSDictionary в качестве параметра в POST - PullRequest
0 голосов
/ 22 марта 2020

Я могу сделать успешный POST-запрос в POSTMAN следующим образом:

{
  "id": "1",
  "myDictKey": {
    "key0": "blah",
    "key1": "blah",
    "key2": "blah"
  } 
}

Однако, когда я пытаюсь сделать этот POST-запрос в быстром, POST не выполняется. Кажется, что параметр NSDictionary не кодируется должным образом.

Swift Code

    let dictParam = ["key0": "blah", "key1": "blah", "key2": "blah"] as NSDictionary
    let urlString = MY_URL
    let url = URL(string: urlString)!
    var request = URLRequest(url: url)
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.httpMethod = "POST"
    let parameters: [String: Any] = [
        "id": "1",
        "myDictKey": dictParam
    ]

    request.httpBody = parameters.percentEncoded()

     let task = URLSession.shared.dataTask(with: request) { data, response, error -> Void in
        if error != nil {
            completion(nil, error?.localizedDescription)
            return
        }

        do {
            if let json = try JSONSerialization.jsonObject(with: data!, options: [.allowFragments]) as? NSDictionary {
                if response?.statusCode() == 200 {
                    if let jsonResponse = json.value(forKeyPath: "response") as? NSDictionary {
                            completion(jsonResponse, nil)
                            return

                } else if response?.statusCode() == 401 {
                    completion(nil, "Unauthorized")
                } else {
                    completion(nil, "Something went wrong. Try again later")
                }
            }
        } catch {
            completion(nil, "Something went wrong. Try again later")
        }
    }
    task.resume()

процентEncoded ()

// MARK: - Dictionary
extension Dictionary {
  func percentEncoded() -> Data? {
    return map { key, value in
        let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
        let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
        return escapedKey + "=" + escapedValue
    }
    .joined(separator: "&")
    .data(using: .utf8)
 }
}

Набор символов

// MARK: - CharacterSet
extension CharacterSet {
    static let urlQueryValueAllowed: CharacterSet = {
    let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
    let subDelimitersToEncode = "!$&'()*+,;="

    var allowed = CharacterSet.urlQueryAllowed
    allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
    return allowed
  }()
}

Ответы [ 2 ]

0 голосов
/ 22 марта 2020

Вы можете создать Кодируемую модель для вашего тела запроса.

Примерно так:

struct MyRequestBodyModel: Encodable {
    let id: String
    let myDictKey: MyNestedModel
}

struct MyNestedModel: Encodable {
    let key0: String
    let key1: String
    let key2: String
}

И после:

do {
    let requestBody = MyRequestBodyModel(...)
    request.httpBody = try JSONEncoder().encode(requestBody)
} catch {
    // Handle error here
}

Я думаю, что этот путь понятнее и проще в обслуживании.

0 голосов
/ 22 марта 2020

Вам нужно JSONSerialize параметр:

request.httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
...