(iOS / Swift) 使用 Key-Value 的简单 Post 请求失败,但使用 Postman 成功

(iOS / Swift) Simple Post Request with Key-Value Failed, But Succeeded using Postman

我使用 Postman 创建了一个简单的 POST 请求并成功了。这是 body 和响应

的屏幕截图

body and response

这是Postmanheader中的截图

header

现在我正在使用 Swift 在 iOS 应用程序中创建一个 POST 请求。这是代码:

public func getResultItem(url: URL, _ completion:@escaping (ResultItem?, Error?) -> Void){
    let parameter = ["uname":"21120113120038", "pass":"123456"]

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type")
    guard let httpBody = try? JSONSerialization.data(withJSONObject: parameter, options: []) else {return}
    request.httpBody = httpBody

    URLSession.shared.dataTask(with: request) { (data, response, error) in
        var resultItem: ResultItem?

        guard let data = data else {
            completion(resultItem, error)
            return
        }

        do {
            resultItem = try JSONDecoder().decode(ResultItem.self, from: data)
            completion(resultItem, error)
        } catch let error as NSError{
            completion(resultItem, error)
        }
    }.resume()
}

问题是,来自 dataTask 完成处理程序的 "data" 始终为 0 字节。看起来我的请求无效,所以它没有返回 JSON。由于数据为0字节,所以在解码JSON时,"do"块总是失败,并转向"catch"块。这里 "catch" 块中的 error.description 是 -> 'The given data was not valid JSON'.

我的代码哪一部分是错误的?我的第一个假设是请求有问题。可能是参数或者httpbody请求有误,不知道怎么解决

谢谢

您的内容类型是 application/x-www-form-urlencoded,但您将正文设置为 JSON 而不是 URL 编码参数。您的 HTTP 正文看起来与您现在拥有的方式类似:

{"uname":"21120113120038","pass":"123456"}

...但您希望它看起来像这样:

uname=21120113120038&pass=123456

所以,替换这一行:

guard let httpBody = try? JSONSerialization.data(withJSONObject: parameter, options: []) else {return}

...像这样:

guard let httpBody = parameter.map({
    [[=13=].addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "",
     .addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? ""].joined(separator: "=")
}).joined(separator: "&").data(using: .utf8) else { return }

(不过,我觉得这有点乱,所以这里有一些扩展来稍微清理一下:)

extension String {
    var urlEncodedQueryKeyOrValue: String {
        return addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? ""
    }
}

extension Dictionary where Key == String, Value == String {
    var wwwFormURLEncodedString: String {
        return map { "\([=14=].urlEncodedQueryKeyOrValue)=\(.urlEncodedQueryKeyOrValue)" }.joined(separator: "&")
    }
}

然后你会像这样使用它:

[...]
guard let httpBody = parameter.wwwFormURLEncodedString.data(using: .utf8) else { return }
request.httpBody = httpBody
[...]