【问题标题】:Parsing a multi-range request response swift快速解析多范围请求响应
【发布时间】:2018-10-20 23:45:14
【问题描述】:
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5
Content-Length: 282

--3d6b6a416f9b5
Content-Type: video/mp4
Content-Range: bytes 0-50/1270

DATA............

--3d6b6a416f9b5
Content-Type: video/mp4
Content-Range: bytes 100-150/1270

eta http-equiv="Content-type" content="text/html; c
--3d6b6a416f9b5--

这是我从 Mozilla 得到的示例响应。我正在使用 swift 并使用 URLSession 创建多部分范围请求。我得到一个响应,我用 ascii 编码转换为[UInt8]String 我可以获得边界字符串。但是我想知道如何才能可靠地提取每个范围请求中的内容,而不管内容类型和内容范围如何。我意识到我可以获得 --3d6b6a416f9b5 .... --3d6b6a416f9b5 块,但如何准确删除内容标题。

let ranges : [(Int, Int)] = [...]
var range_request = "bytes="
for r in ranges {
    range_request += "\(r.0)-\(r.1), "
}
range_request = String(range_request.dropLast(2))
var streamRequest = URLRequest(url: streamURL)
streamRequest.setValue(range_request, forHTTPHeaderField: "Range")
let sessionConfig = URLSessionConfiguration.default
sessionConfig.timeoutIntervalForRequest = 1
let session = URLSession(configuration: sessionConfig)
let task = session.downloadTask(with: streamRequest) { (tempLocalURL, response, url_error) in
    if url_error != nil {
        //handle error
    } else {
        do {
            //assume successful 206 response for now...
            let httpResponse = response as! HTTPURLResponse 
            let data = try Data(contentsOf: tempLocalURL!)
            let boundaryPhrase = (httpResponse.allHeaderFields["Content-Type"]! as! String).replacingOccurrences(of: "multipart/byteranges; boundary=", with: "")
            let totalData = [UInt8](data)
            let stringTotalData = (String(data: data, encoding: .ascii)!

        } catch {
            //handle error
        }
    }
}
task.resume()

【问题讨论】:

    标签: swift http range nsurlsession


    【解决方案1】:
    let data = try Data(contentsOf: tempLocalURL!)
    let content_type = httpResponse.allHeaderFields["Content-Type"]! as! String
    let boundary_word = content_type.replacingOccurrences(of: "multipart/byteranges; boundary=", with: "")
    let boundary_phrase = "--\(boundary_word)"
    let input_data = [UInt8](data)
    var bodies : [[UInt8]] = []
    var current_body = 0
    if boundary_word != "video/mp4" {
        let boundary_phrase_ints = [UInt8](boundary_phrase.utf8)
        let header_end_ints = [UInt8]("\r\n\r\n".utf8)
        var i = 0
        var potential_body : [UInt8] = []
        while i < (input_data.count - boundary_phrase_ints.count) {
            if potential_body == boundary_phrase_ints {
                let potential_end_header = Array(input_data[i..<(i + header_end_ints.count)])
                if potential_end_header == header_end_ints {
                    let start = i + header_end_ints.count
                    let upper_limit = start + ranges[current_body].1 - ranges[current_body].0
                    bodies.append(Array(input_data[start...upper_limit]))
                    current_body += 1
                    i = upper_limit
                }
            } else {
                potential_body = Array(input_data[i..<(i + boundary_phrase_ints.count)])
                if potential_body == boundary_phrase_ints {
                    i += boundary_phrase_ints.count
                }
            }
            i += 1
        }
        //in my case I don't need to split the data into separate ranges.
    } else {
        //handle single range case
    }
    

    所以我能够解决问题。这是我的代码。在我的情况下,我需要将数据处理为 [UInt8] 因为它是我请求的视频,这就是为什么我必须将边界短语转换为 [UInt8] 以及标题结尾。

    因此,通过使用边界短语,您可以提取每个主体 - 如果您使用字符串执行此操作,您可以只做组件并删除第一个和最后一个元素,因为这些是伪造的。接下来在每个正文中,您可以通过查找似乎是唯一的“\r\n\r\n”来找到标题的结尾。

    【讨论】:

      猜你喜欢
      • 2017-08-27
      • 2013-02-20
      • 1970-01-01
      • 2017-10-16
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多