在Swift中解析多部分SOAP响应。

问题描述 投票:1回答:1

我试图从肥皂服务中下载一个文件,在请求成功后得到以下信息

响应头

multipart/related; type="application/xop+xml"; boundary="uuid:917b60a9-3089-43ad-a8c2-b4a3c62db98c"; start="<[email protected]>"; start-info="text/xml"

回应体

--uuid:0a679f64-0753-44fe-b627-2267b5b72b1d
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary
Content-ID: <[email protected]>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:leseDokumentResponse xmlns:ns2="http://webservice/"><return><status>OK</status><dokument><xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:[email protected]"/></dokument></return></ns2:leseDokumentResponse></soap:Body></soap:Envelope>
--uuid:0a679f64-0753-44fe-b627-2267b5b72b1d
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <[email protected]>

... binary data ...
--uuid:0a679f64-0753-44fe-b627-2267b5b72b1d--

如何解析文件二进制数据?

我试过这些问题,但没有任何效果 解析http-multipart响应 在ios中解析图片下载的多部分响应。

swift soap alamofire multipart urlsession
1个回答
0
投票

通过使用以下方法可以很容易地解析多部分SOAP响应。多部件套件

我创建了一个关于 Alamofire's DataResponse 来处理响应

import Alamofire
import MultipartKit
import Swime

extension DataResponse where Success == Data {

    var boundary: String? {

        let header = response?.allHeaderFields.first(where: {
            $0.key as? String == "Content-Type"
        })

        let scanner = Scanner(string: header?.value as? String ?? "")

        _ = scanner.scanUpToString("boundary=\"")
        _ = scanner.scanString("boundary=\"")
        let boundary = scanner.scanUpToString("\";")

        return boundary
    }

    func multipartParts() -> [MultipartPart] {

        guard let boundary = boundary else { return [] }

        guard let data = try? result.get() else { return [] }

        let parser = MultipartParser(boundary: boundary)

        var parts: [MultipartPart] = []
        var headers: HTTPHeaders = [:]
        var body: Data = Data()

        parser.onHeader = { (field, value) in
            headers.replaceOrAdd(name: field, value: value)
        }
        parser.onBody = { new in
            body.append(contentsOf: new.readableBytesView)
        }
        parser.onPartComplete = {
            let part = MultipartPart(headers: headers, body: body)
            headers = [:]
            body = Data()
            parts.append(part)
        }

        do {
            try parser.execute(data)
        } catch {
            print(error.localizedDescription)
        }

        return parts
    }

    func parseMultipart() -> (message: String, files: [Data])? {

        let parts = multipartParts()

        let message = parts.first(where: { $0.id == "<[email protected]>" })?.body.string ?? ""

        let dataPart = parts.filter { $0.id != "<[email protected]>" }

        let files = dataPart.compactMap { Data(multipart: $0) }

        return (message, files)
    }
}

extension ByteBuffer {
    var string: String {
        return String(decoding: self.readableBytesView, as: UTF8.self)
    }
}

extension MultipartPart {

    /// Gets or sets the `name` attribute from the part's `"Content-ID"` header.
    public var id: String? {
        get { self.headers.first(name: "Content-ID") }
    }
}

然后可以用于这样的数据响应。

let request = SessionManager.request(urlRequest).responseData(completionHandler: { response in

    switch response.result {
        case .failure(let error):
            self.alert(error)

        case .success:

            guard let parts = response.parseMultipart() else { return }

            DispatchQueue.main.async {

                self.loadResponse(message: parts.message, files: parts.files)
        }
    }
})

消息的id可能不同,所以我建议也检查一下类型。

希望能帮到大家。

© www.soinside.com 2019 - 2024. All rights reserved.