【问题标题】:How can I make a POST Request in Swift with parameters using URLSession如何使用 URLSession 在 Swift 中使用参数发出 POST 请求
【发布时间】:2022-01-24 13:19:29
【问题描述】:

我有一个要使用 URLSession 发出的发布请求。

发布请求如下所示:

curl -X POST   'https://smartdevicemanagement.googleapis.com/v1/enterprises/privatekey/devices/devicekey:executeCommand'   -H 'Content-Type: application/json'   -H 'Authorization: authtoken'   --data-raw '{
"command" : "sdm.devices.commands",
"params" : {
  "commandName" : "cmdValue"
 }
}'

由于这是一个 POST 请求,我只想在响应是错误消息时进行解码。

这是我目前拥有的代码:

guard let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") else {return}
    
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("token", forHTTPHeaderField: "Authorization")
let cmdParams: [String: String] =  ["command":"sdm.devices.commands", "params" : ["commandName": "cmdValue"]]

do {
    request.httpBody = try JSONSerialization.data(withJSONObject: cmdParams)
} catch let error {
    print(error.localizedDescription)
    }

URLSession.shared.dataTask(with: request) { (data, response, error) in
    guard error == nil else {print(error!.localizedDescription); return }
    guard let data = data else {print("empty data"); return }

cmdParams 抛出错误,所以我不确定如何正确构造 params 请求,成功的 POST 将导致 API 返回 {} 不成功的请求将返回一些错误。

如何调整我的代码以使其正常工作?

【问题讨论】:

  • cmdParams[String:Any],而不是 [String:String]
  • @vadian 感谢进行了更改,但仍然无法将请求发送到 POST。
  • [String:Any] 不可编码。您要么需要创建一个 struct 来对数据进行编码,要么直接使用 JSON 字符串(如我的回答)。
  • @BjornB。 JSONSerialization 可以序列化[String:Any]。这不是关于Codable
  • @vadian 你是对的。

标签: swift swiftui nsurlsession urlsession


【解决方案1】:

您需要将 JSON 字符串编码为数据。然后您可以将其添加为httpBody.,不要忘记将令牌添加到请求中。

// Encode your JSON data
let jsonString = "{ \"command\" : \"sdm.devices.commands\", \"params\" : { \"commandName\" : \"cmdValue\" } }"
guard let jsonData = jsonString.data(using: .utf8) else { return } 

// Send request
guard let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") else {return}
    
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = jsonData

request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("token", forHTTPHeaderField: "Authorization") // Most likely you want to add some token here
// request.setValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization")

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
    if let error = error {
        // Handle HTTP request error
    } else if let data = data {
        // Handle HTTP request response
    } else {
        // Handle unexpected error
    }
}
task.resume()

【讨论】:

  • 谢谢,现在没有错误消息,但是 POST 数据仍然没有通过,有什么办法可以修改此代码以打印 API 调用响应的内容?
  • 可以,可以打印dataresponse。查看dataTask 文档:developer.apple.com/documentation/foundation/urlsession/…
  • 好的,我收到了一个response code 500,这表明我请求的服务器有问题?
  • 500 通常是内部服务器错误。您有状态消息或响应正文吗?
【解决方案2】:

您可以尝试使用“urlencoded”来编码您的请求正文。这是我的测试代码: (注意,由于我没有付费订阅此服务,我无法完全测试我的代码)

struct ContentView: View {
    let project_id = 123  // <-- adjust to your needs
    
    var body: some View {
        Text("testing")
            .onAppear {
                if let url = URL(string: "https://smartdevicemanagement.googleapis.com/v1/enterprises/\(project_id)/devices") {
                    doPOST(url: url)
                }
            }
    }
    
    func doPOST(url: URL) {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        // try urlencoding
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.setValue("token", forHTTPHeaderField: "Authorization") // <-- your api "token" here
        
        var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!
        components.queryItems = [
            URLQueryItem(name: "command", value: "sdm.devices.commands"),
            URLQueryItem(name: "params", value: "{ \"commandName\" : \"cmdValue\" }")
        ]
        if let query = components.url!.query {
            print("--> query: \(query)")
            request.httpBody = Data(query.utf8)
        }
        
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            showResponse(data)  // <-- for debuging
            guard error == nil else { print("--> error: \(error)"); return }
            guard let data = data else { print("empty data"); return }
        }
        task.resume()
    }
    
    func showResponse(_ data: Data?) {
        if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers), let jsonData = try? JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) {
            print("\n---> response: " + String(decoding: jsonData, as: UTF8.self))
        } else {
            print("=========> error")
        }
    }
    
}

如果这不起作用,请查看此文档:

https://developers.google.com/nest/device-access/reference/rest/v1/enterprises.devices/executeCommand

特别是:The URL uses gRPC Transcoding syntax。这可能是相关的。

【讨论】:

    猜你喜欢
    • 2017-04-10
    • 2011-04-28
    • 1970-01-01
    • 2017-09-13
    • 2015-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    相关资源
    最近更新 更多