在 Swift 中为 SOAP POST 从 NSURLConnection 迁移到 NSURLSession

Posted

技术标签:

【中文标题】在 Swift 中为 SOAP POST 从 NSURLConnection 迁移到 NSURLSession【英文标题】:Moving from NSURLConnection to NSURLSession for SOAP POST in Swift 【发布时间】:2015-09-30 10:18:26 【问题描述】:

我正在尝试从 NSURLConnection 转移到 NSURLSession 以进行 SOAP 发布,但 NSURLSessionDataDelegate 似乎存在问题。

这是 NSURLConnection 中运行良好的旧代码:

let soapMessage = "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ns1='http://tempuri.org/'><SOAP-ENV:Body><ns1:get_Countries/></SOAP-ENV:Body></SOAP-ENV:Envelope>"
    print("Soap Packet is \(soapMessage)")

    let urlString = "https://example.com/Service.svc"
    let url = NSURL(string: urlString)
    let theRequest = NSMutableURLRequest(URL: url!)
    let msgLength = String(soapMessage.characters.count)

    theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
    theRequest.addValue(msgLength, forHTTPHeaderField: "Content-Length")
    theRequest.addValue("http://tempuri.org/IService/get_Countries", forHTTPHeaderField: "SoapAction")
    theRequest.HTTPMethod = "POST"
    theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    print("Request is \(theRequest.allHTTPHeaderFields!)")

    let connection = NSURLConnection(request: theRequest, delegate: self, startImmediately: false)
    connection?.start()

此代码然后使用 NSURLConnectionDelegate,并且工作正常,如下所示:

func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) 
    MutableData.length = 0;
    let httpresponse = response as? NSHTTPURLResponse
    print("status \(httpresponse?.statusCode)")
    //print("headers \(httpresponse?.allHeaderFields)")


func connection(connection: NSURLConnection!, didReceiveData data: NSData!) 
    MutableData.appendData(data)



func connection(connection: NSURLConnection, didFailWithError error: NSError) 
    NSLog("Error with Soap call: %@", error)



func connectionDidFinishLoading(connection: NSURLConnection!) 
    let xmlParser = NSXMLParser(data: MutableData)
    xmlParser.delegate = self
    xmlParser.parse()
    xmlParser.shouldResolveExternalEntities = true


func connection(connection: NSURLConnection, willSendRequestForAuthenticationChallenge challenge: NSURLAuthenticationChallenge) 
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust && challenge.protectionSpace.host == "example.com" 
        NSLog("yep")
        let credential = NSURLCredential(trust: challenge.protectionSpace.serverTrust!)
        challenge.sender!.useCredential(credential, forAuthenticationChallenge: challenge)
     else 
        NSLog("nope")
        challenge.sender!.performDefaultHandlingForAuthenticationChallenge!(challenge)
    

所以这些代码都可以正常工作,仅供参考,这样您就可以看到我过去所做的事情,以及 API 确实可以工作的事实!但是,如果我转而使用 NSURLSession 和 NSURLSessionDataDelegate ,那么我将无法使其正常工作。

所以这是新代码:

let soapMessage = "<?xml version='1.0' encoding='UTF-8'?><SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ns1='http://tempuri.org/'><SOAP-ENV:Body><ns1:get_Countries/></SOAP-ENV:Body></SOAP-ENV:Envelope>"
    print("Soap Packet is \(soapMessage)")

    let urlString = "https://example.com/Service.svc"
    let url = NSURL(string: urlString)
    let theRequest = NSMutableURLRequest(URL: url!)
    let msgLength = String(soapMessage.characters.count)

    theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
    theRequest.addValue(msgLength, forHTTPHeaderField: "Content-Length")
    theRequest.addValue("http://tempuri.org/IService/get_Countries", forHTTPHeaderField: "SoapAction")
    theRequest.HTTPMethod = "POST"
    theRequest.HTTPBody = soapMessage.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
    print("Request is \(theRequest.allHTTPHeaderFields!)")

let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration:config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
let task = session.dataTaskWithRequest(theRequest)
task.resume()

我使用的代理是 NSURLSessionDelegate、NSURLSessionDataDelegate:

func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) 

    print("Am in NSURLSessionDelegate didReceiveChallenge")

    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust && challenge.protectionSpace.host == "example.com" 
        NSLog("yep authorised")
        let credential = NSURLCredential(trust: challenge.protectionSpace.serverTrust!)
        challenge.sender!.useCredential(credential, forAuthenticationChallenge: challenge)
     else 
        NSLog("nope")
        challenge.sender!.performDefaultHandlingForAuthenticationChallenge!(challenge)
    


func URLSessionDidFinishEventsForBackgroundURLSession(session: NSURLSession) 
    print("Am in URLSessionDidFinishEventsForBackgroundURLSession")
    let xmlParser = NSXMLParser(data: MutableData)
    xmlParser.delegate = self
    xmlParser.parse()
    xmlParser.shouldResolveExternalEntities = true

func URLSession(session: NSURLSession, didBecomeInvalidWithError error: NSError?) 
    print("error of \(error)")


func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) 
    print("Am in didReceiveResponse")
    MutableData.length = 0



func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) 
    print("Am in didReceiveData")
    MutableData.appendData(data)


func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) 
    print("error of \(error)")

所以,当我运行代码时,我会得到输出:

“我在 NSURLSessionDelegate didReceiveChallenge” “是的,授权”

所以它可以很好地进入didReceiveChallenge,并且它似乎可以很好地授权HTTPS安全证书,但是没有进一步的事情发生,它没有做任何其他事情,我希望它进入didReceiveResponse然后didReceiveData,但没有进一步发生。

所以我被卡住了,我当然可以继续使用 NSURLConnection,因为它一切正常,但我想了解 NSURLSession,特别是我哪里出错了。因此,如果有人能提供帮助,那就太好了。

谢谢

【问题讨论】:

【参考方案1】:

如果其他人有同样的问题,我解决了这个问题。问题是我没有在 didReceiveChallenge 和 didReceiveResponse 代表中使用 completionHandler

【讨论】:

如果你解决了,你能发布答案吗?拜托?我也确实需要帮助。【参考方案2】:
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) 

completionHandler(NSURLSessionResponseDisposition.Allow) //.Cancel,如果要停止下载

【讨论】:

以上是关于在 Swift 中为 SOAP POST 从 NSURLConnection 迁移到 NSURLSession的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift Alamofire 从 SOAP 中提取 JSON 数据

在 Swift 中解析多部分 SOAP 响应

XSLT转换需要添加SOAP信封并在SOAP标头和正文之间拆分XML

41241234124

从 Soap Envelope 请求中解析数据

SOAP UI中的特殊字符关闭标记问题