我有一个NSURLProtocol在UIWebView上监听POST请求。我尝试捕获 POST 参数并首先在这里阅读 httpBody 始终为零,因为正文数据对象被转换为流样式的主体。
然后,我使用以下扩展打开 HTTPBodyStream 对象并从中读取正文数据。
extension InputStream {
func readfully() -> Data {
var result = Data()
var buffer = [UInt8](repeating: 0, count: 4096)
open()
var amount = 0
repeat {
amount = read(&buffer, maxLength: buffer.count)
if amount > 0 {
result.append(buffer, count: amount)
}
} while amount > 0
close()
return result
}
}
问题是我的身体从输入流读取的数据也是零。在MyUrlProtocol中,我覆盖了以下方法。
override class func canInit(with request: URLRequest) -> Bool
if request.httpMethod == "POST" {
print(request.url?.absoluteString) //ok show correct POST url
let bodyData = request.httpBodyStream?.readfully() //nil
print(String(data: bodyData!, encoding: String.Encoding.utf8))
return true
}
return false
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
let bodyData = self.request.httpBodyStream?.readfully() //nil
}
override func stopLoading() {
let bodyData = self.request.httpBodyStream?.readfully() //nil
}
为什么 httpBodyStream 在我的自定义 NSURLProtocol 中也是 Nil?
我可以使用网络浏览器中的网络开发工具正确查看同一 URL 的 POST 参数。
您无法像这样同步从流中读取。 您必须等待字节在流中可用,然后读取,然后再次等待,依此类推,直到其中一个读取返回零字节。 如果没有等待部分,您就不会读取 while 的东西,因为读取数据的代码几乎肯定会阻塞应该填充流对另一端的线程。
下面介绍了从流中读取的完整步骤集:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html
如果数据太大而无法放入 RAM,则可能需要在解析数据时将各种位写入磁盘,然后提供新的输入流。
无论哪种方式,您都必须异步执行此操作。