Moving from NSURLConnection to NSURLSession for SO

2019-05-30 00:52发布

问题:

I am trying to move over from NSURLConnection over to NSURLSession for a SOAP post, but seem to have issues with the NSURLSessionDataDelegate.

Here is the old code in NSURLConnection that works fine:

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()

This code then uses NSURLConnectionDelegate, and works fine as follows:

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)
    }
}

So that code all works fine, and is just for reference so you can see what I have done in the past, and the fact that the API actually does work! However, if I move over to using NSURLSession and NSURLSessionDataDelegate instead then I cannot get it working correctly.

So here is the new code:

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()

My delegates I am using are 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)")
}

So, when I run the code, I get output:

"Am in NSURLSessionDelegate didReceiveChallenge" "yep authorised"

So it's getting to didReceiveChallenge fine, and it appears to be authorising the HTTPS secure certificate fine, but then nothing further happens, it doesn't do anything else, I'd expect it to go into didReceiveResponse then didReceiveData, but nothing further happens at all.

So I am stuck, I could of course continue and use NSURLConnection as it all works fine, but I'd like to understand the NSURLSession, and particulary where I am going wrong. So if anyone can help that would be great.

Thanks

回答1:

In case anyone else has the same issue, I sorted this out. The issue was I was not using the completionHandler in the didReceiveChallenge and didReceiveResponse delegates



回答2:

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {

completionHandler(NSURLSessionResponseDisposition.Allow) //.Cancel,If you want to stop the download }