为什么 NSURLProtocol 子类中请求的 HTTPBody 始终为零?
Why is the HTTPBody of a request inside an NSURLProtocol Subclass always nil?
我有我的 NSURL协议 MyGreatProtocol
。我将它添加到 URL 加载系统,
NSURLProtocol.registerClass(MyGreatProtocol)
然后我开始在网络 session 期间接收 MyGreatProtocol
内的事件。
假设我在注册我的协议后创建 session,
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string:"http://example.com")!, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 2.0) //arbitrary 404
request.HTTPBody = ([1, 3, 3, 7] as [UInt8]).toNSData
print("body data: \(request.HTTPBody)") //prints `Optional(<01030307>)`
request.HTTPMethod = "POST"
session.dataTaskWithRequest(request) { (data, response, err) in
print("data: \(data)\nresponse: \(response)\nerror\(err)")
}.resume()
我希望请求的 HTTP body 1/3/3/7
出现在 MyGreatProtocol
中,但实际上没有。
在 MyGreatProtocol
中,我覆盖了以下方法。
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
print(request.HTTPBody) //prints nil
return request
}
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
print(request.HTTPBody) //prints nil
return true
}
override func startLoading() {
print(self.request.HTTPBody) //prints nil
}
NSURLRequest 的其他属性似乎被保留。 URL、HTTP 动词、headers 等都在那里。关于 body 的性质的一些具体内容仍然难以捉摸。
为什么自定义 NSURL 协议中的 HTTP Body 为 Nil?
之前提交的雷达似乎有一些类似的讨论(即https://bugs.webkit.org/show_bug.cgi?id=137299)
IIRC,正文数据对象在到达您之前由 URL 加载系统透明地转换为流式正文。如果需要读取数据:
- 打开 HTTPBodyStream 对象
- 从中读取正文数据
有一个警告:流可能无法倒带,所以不要将该请求对象传递给之后需要访问正文的任何其他代码。不幸的是,也没有请求新主体流的机制(有关其他限制,请参阅 Apple 网站上 CustomHTTPProtocol 示例代码项目中的 README 文件)。
这是读取 httpBody 的示例代码:
Swift 5
extension URLRequest {
func bodySteamAsJSON() -> Any? {
guard let bodyStream = self.httpBodyStream else { return nil }
bodyStream.open()
// Will read 16 chars per iteration. Can use bigger buffer if needed
let bufferSize: Int = 16
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
var dat = Data()
while bodyStream.hasBytesAvailable {
let readDat = bodyStream.read(buffer, maxLength: bufferSize)
dat.append(buffer, count: readDat)
}
buffer.deallocate()
bodyStream.close()
do {
return try JSONSerialization.jsonObject(with: dat, options: JSONSerialization.ReadingOptions.allowFragments)
} catch {
print(error.localizedDescription)
return nil
}
}
}
然后,在 URLProtocol 中:
override func startLoading() {
...
if let jsonBody = self.request.bodySteamAsJSON() {
print("JSON \(jsonBody)")
}
...
}
我有我的 NSURL协议 MyGreatProtocol
。我将它添加到 URL 加载系统,
NSURLProtocol.registerClass(MyGreatProtocol)
然后我开始在网络 session 期间接收 MyGreatProtocol
内的事件。
假设我在注册我的协议后创建 session,
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string:"http://example.com")!, cachePolicy: .ReloadIgnoringLocalCacheData, timeoutInterval: 2.0) //arbitrary 404
request.HTTPBody = ([1, 3, 3, 7] as [UInt8]).toNSData
print("body data: \(request.HTTPBody)") //prints `Optional(<01030307>)`
request.HTTPMethod = "POST"
session.dataTaskWithRequest(request) { (data, response, err) in
print("data: \(data)\nresponse: \(response)\nerror\(err)")
}.resume()
我希望请求的 HTTP body 1/3/3/7
出现在 MyGreatProtocol
中,但实际上没有。
在 MyGreatProtocol
中,我覆盖了以下方法。
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
print(request.HTTPBody) //prints nil
return request
}
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
print(request.HTTPBody) //prints nil
return true
}
override func startLoading() {
print(self.request.HTTPBody) //prints nil
}
NSURLRequest 的其他属性似乎被保留。 URL、HTTP 动词、headers 等都在那里。关于 body 的性质的一些具体内容仍然难以捉摸。
为什么自定义 NSURL 协议中的 HTTP Body 为 Nil?
之前提交的雷达似乎有一些类似的讨论(即https://bugs.webkit.org/show_bug.cgi?id=137299)
IIRC,正文数据对象在到达您之前由 URL 加载系统透明地转换为流式正文。如果需要读取数据:
- 打开 HTTPBodyStream 对象
- 从中读取正文数据
有一个警告:流可能无法倒带,所以不要将该请求对象传递给之后需要访问正文的任何其他代码。不幸的是,也没有请求新主体流的机制(有关其他限制,请参阅 Apple 网站上 CustomHTTPProtocol 示例代码项目中的 README 文件)。
这是读取 httpBody 的示例代码:
Swift 5
extension URLRequest {
func bodySteamAsJSON() -> Any? {
guard let bodyStream = self.httpBodyStream else { return nil }
bodyStream.open()
// Will read 16 chars per iteration. Can use bigger buffer if needed
let bufferSize: Int = 16
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
var dat = Data()
while bodyStream.hasBytesAvailable {
let readDat = bodyStream.read(buffer, maxLength: bufferSize)
dat.append(buffer, count: readDat)
}
buffer.deallocate()
bodyStream.close()
do {
return try JSONSerialization.jsonObject(with: dat, options: JSONSerialization.ReadingOptions.allowFragments)
} catch {
print(error.localizedDescription)
return nil
}
}
}
然后,在 URLProtocol 中:
override func startLoading() {
...
if let jsonBody = self.request.bodySteamAsJSON() {
print("JSON \(jsonBody)")
}
...
}