(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
[...]
我使用 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
[...]