iOS swift post 二进制请求 body
iOS swift post request with binary body
我想从 iOS (swift3) 发出一个 POST 请求,它将一大块原始字节作为 body 传递。我做了一些实验,使我认为以下方法有效:
let url = URL(string: "https://bla/foo/bar")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = Data(hex: "600DF00D")
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
"DATA \(data ?? Data()) RESPONSE \(response) ERROR \(error)".print()
}
task.resume()
在我尝试发送像单个 0xF0 这样简单的东西之前,我不知道这是一个问题。此时我的龙卷风服务器开始抱怨我正在发送它
WARNING:tornado.general:Invalid x-www-form-urlencoded body: 'utf-8' codec can't decode byte 0xf0 in position 2: invalid continuation byte
我是否应该以某种方式设置一些 header?还是我需要做一些不同的事情?
两种常见的解决方案是:
您的错误消息告诉我们网络服务正在等待 x-www-form-urlencoded
请求(例如 key=value
),对于 value
,您可以执行二进制有效载荷的 base-64 编码。
不幸的是,base-64 字符串仍然需要进行百分比转义(因为 Web 服务器通常将 +
个字符解析为空格),因此您必须执行以下操作:
let base64Encoded = data
.base64EncodedString(options: [])
.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
.data(using: String.Encoding.utf8)!
var body = "key=".data(using: .utf8)!
body.append(base64Encoded)
var request = URLRequest(url: url)
request.httpBody = body
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
print(error!)
return
}
...
}
task.resume()
其中:
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 点:。
无论如何,当你在你的服务器上收到这个时,你可以检索它然后反转 base-64 编码,你将拥有你的原始二进制有效负载。
或者,您可以使用 multipart/formdata
请求(您可以在其中提供二进制负载,但必须将其包装为更广泛的 multipart/formdata
格式的一部分)。如果您想自己执行此操作,请参阅 。
对于这两种方法,像 Alamofire 这样的库使它变得更加容易,让您摆脱构建这些请求的杂草。
我想从 iOS (swift3) 发出一个 POST 请求,它将一大块原始字节作为 body 传递。我做了一些实验,使我认为以下方法有效:
let url = URL(string: "https://bla/foo/bar")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = Data(hex: "600DF00D")
let session = URLSession.shared
let task = session.dataTask(with: request) { (data, response, error) in
"DATA \(data ?? Data()) RESPONSE \(response) ERROR \(error)".print()
}
task.resume()
在我尝试发送像单个 0xF0 这样简单的东西之前,我不知道这是一个问题。此时我的龙卷风服务器开始抱怨我正在发送它
WARNING:tornado.general:Invalid x-www-form-urlencoded body: 'utf-8' codec can't decode byte 0xf0 in position 2: invalid continuation byte
我是否应该以某种方式设置一些 header?还是我需要做一些不同的事情?
两种常见的解决方案是:
您的错误消息告诉我们网络服务正在等待
x-www-form-urlencoded
请求(例如key=value
),对于value
,您可以执行二进制有效载荷的 base-64 编码。不幸的是,base-64 字符串仍然需要进行百分比转义(因为 Web 服务器通常将
+
个字符解析为空格),因此您必须执行以下操作:let base64Encoded = data .base64EncodedString(options: []) .addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)! .data(using: String.Encoding.utf8)! var body = "key=".data(using: .utf8)! body.append(base64Encoded) var request = URLRequest(url: url) request.httpBody = body request.httpMethod = "POST" request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") let task = URLSession.shared.dataTask(with: request) { data, response, error in guard error == nil else { print(error!) return } ... } task.resume()
其中:
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 点:。
无论如何,当你在你的服务器上收到这个时,你可以检索它然后反转 base-64 编码,你将拥有你的原始二进制有效负载。
或者,您可以使用
multipart/formdata
请求(您可以在其中提供二进制负载,但必须将其包装为更广泛的multipart/formdata
格式的一部分)。如果您想自己执行此操作,请参阅 。
对于这两种方法,像 Alamofire 这样的库使它变得更加容易,让您摆脱构建这些请求的杂草。