【问题标题】:Why is the HTTPBody of a request inside an NSURLProtocol Subclass always nil?为什么 NSURLProtocol 子类中的请求的 HTTPBody 总是为零?
【发布时间】:2016-08-01 23:43:20
【问题描述】:

我有我的 NSURLProtocol MyGreatProtocol。我将它添加到 URL 加载系统中,

NSURLProtocol.registerClass(MyGreatProtocol)

然后我开始在网络会话期间接收 MyGreatProtocol 内部的事件。

假设我在注册协议后创建会话,

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 正文 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 动词、标头等都在那里。关于身体性质的一些具体情况仍然难以捉摸。

为什么 HTTP Body Nil 在自定义 NSURLProtocol 中?

之前提交的雷达似乎有一些类似的讨论(即https://bugs.webkit.org/show_bug.cgi?id=137299

【问题讨论】:

    标签: ios swift nsurlprotocol


    【解决方案1】:

    IIRC,正文数据对象在到达您之前通过 URL 加载系统透明地转换为流式正文。如果需要读取数据:

    • 打开 HTTPBodyStream 对象
    • 从中读取正文数据

    有一个警告:流可能不可回退,因此不要将该请求对象传递给任何其他需要访问主体的代码。不幸的是,也没有请求新正文流的机制(有关其他限制,请参阅 Apple 网站上 CustomHTTPProtocol 示例代码项目中的 README 文件)。

    【讨论】:

    • HTTPBodyStream 里面也没有数据
    • 那么你发现了一个错误。那应该是不可能的。
    • 我将这个问题的代码复制到canInitWithRequest: 并得到了inputStream.read stackoverflow.com/questions/25476770/… 的-1 返回值
    • 你先打开直播了吗?
    • 绝妙的答案!我没有意识到我需要在读取之前打开流。非常感谢:)
    【解决方案2】:

    这是一个读取httpBody的示例代码:

    斯威夫特 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)")
    
        }
    
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多