Предотвращение перенаправления URLSession в Swift

мне нужно получить URL перенаправления, но предотвратить перенаправление в Swift. Из других сообщений и документов Apple я понимаю, что должен реализовать метод делегата URLSession(session:, task:, willPerformHTTPRedirection response:, request:, completionHandler:) и возврат nil через закрытие завершение. Но я не могу найти примеры в swift и не могу понять, как это сделать. Приведенный ниже код воспроизводит мою проблему в playground: делегат, похоже, не выполняется.

import Foundation
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

class MySession: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate {

    // trying to follow instructions at https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionTaskDelegate_protocol/index.html#//apple_ref/occ/intfm/NSURLSessionTaskDelegate/URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:
    // to prevent redirection -- DOES NOT SEEM TO GET CALLED
    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest!) -> Void) {
        println("in URLSession delegate") // NEVER PRINTS
        completionHandler(nil) // NO EFFECT
    }

    // fetch data from URL with NSURLSession
    class func getDataFromServerWithSuccess(myURL: String, success: (response: String!) -> Void) {
        var session = NSURLSession.sharedSession()
        let loadDataTask = session.dataTaskWithURL(NSURL(string: myURL)!) { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
            // OMITTING ERROR CHECKING FOR BREVITY
            success(response: NSString(data: data!, encoding: NSASCIIStringEncoding) as String)
        }
        loadDataTask.resume()
    }

    // extract data from redirect
    class func getRedirectionInfo(url: String) {
        getDataFromServerWithSuccess(url) {(data) -> Void in
            if let html = data {
                if html.rangeOfString("<html><head><title>Object moved</title>", options: .RegularExpressionSearch) != nil {
                    println("success: redirection was prevented") // SHOULD PRINT THIS
                } else {
                    println("failure: redirection went through") // INSTEAD PRINTS THIS
                }
            }
        }
    }
}

MySession.getRedirectionInfo("http://bit.ly/filmenczer") // ex. redirecting link

пожалуйста, будьте нежны, я новичок. заранее спасибо любая помощь!

обновление: С большой благодарностью @nate я получил его на работу. Ключевым моментом является то, что для вызова делегата необходимо пропуск класса delegate до NSURLSession() инициализатор, а не с помощью NSURLSession.sharedSession(). Проходя nil как делегат дает обычное поведение (с перенаправлением). Вот рабочая версия кода:

import Foundation
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

class MySession: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate {

    // to prevent redirection
    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest!) -> Void) {
        completionHandler(nil)
    }

    // fetch data from URL with NSURLSession
    class func getDataFromServerWithSuccess(myURL: String, noRedirect: Bool, success: (response: String!) -> Void) {
        var myDelegate: MySession? = nil
        if noRedirect {
            myDelegate = MySession()
        }
        let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: myDelegate, delegateQueue: nil)
        let loadDataTask = session.dataTaskWithURL(NSURL(string: myURL)!) { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
            // OMITTING ERROR CHECKING FOR BREVITY
            success(response: NSString(data: data!, encoding: NSASCIIStringEncoding) as String)
        }
        loadDataTask.resume()
    }

    // extract data from redirect
    class func getRedirectionInfo(url: String) {
        getDataFromServerWithSuccess(url, noRedirect: true) {(data) -> Void in
            if let html = data {
                if html.rangeOfString("<html>n<head><title>Bitly</title>", options: .RegularExpressionSearch) != nil {
                    println("success: redirection was prevented")
                } else {
                    println("failure: redirection went through")
                }
            }
        }
    }
}

MySession.getRedirectionInfo("http://bit.ly/filmenczer")

2 ответов


у вас есть две вещи стоят на вашем пути с вашей текущей реализации.

  1. вы никогда не устанавливаете свойство delegate на NSURLSession экземпляр, который вы используете, чтобы сделать запрос. Без набора свойств delegate ваши методы делегата никогда не будут вызываться. Вместо того, чтобы NSURLSession.sharedSession(), посмотри NSURLSession(configuration:delegate:delegateQueue:) инициализатор. Первый и последний параметры могут быть NSURLSessionConfiguration.defaultSessionConfiguration() и nil, соответственно, см. ниже о делегат.

    обратите внимание, что при использовании варианта session.dataTaskWithURL который имеет обработчик завершения, методы делегирования, которые обрабатывают ответ и доставку данных, будут проигнорированы, но обработчики аутентификации и перенаправления все еще используются.

  2. вам придется несколько переработать, чтобы использовать MySession как делегат, так как вы используете методы класса для выполнения запроса. Вам нужен экземпляр для использования в качестве делегата сеанса.

Я взял короткий и неполный маршрут к тому, чтобы делегат забрал перенаправление с помощью этого альтернативного кода-вам нужно будет рефакторировать, как в #3, чтобы убедиться, что вы все еще можете вызвать обратный вызов:

class func getDataFromServerWithSuccess(myURL: String, success: (response: String!) -> Void) {
    let delegate = MySession()
    var session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: delegate, delegateQueue: nil)
    let task = session.dataTaskWithURL(NSURL(string: myURL)!) {
        // ...
    } 
    task.resume()
}

надеюсь, что это поможет!


незначительные корректировки предложенных выше решений. Это работает с Swift 2 в XCode 7.

import UIKit
import Foundation
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely(true)

class MySession: NSObject, NSURLSessionDelegate {

    // to prevent redirection
    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest!) -> Void) {
    completionHandler(nil)
    }

    // fetch data from URL with NSURLSession
    class func getDataFromServerWithSuccess(myURL: String, noRedirect: Bool, success: (response: String!) -> Void) {
    var myDelegate: MySession? = nil
    if noRedirect {
        myDelegate = MySession()
    }
    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: myDelegate, delegateQueue: nil)
    let loadDataTask = session.dataTaskWithURL(NSURL(string: myURL)!) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
        // OMITTING ERROR CHECKING FOR BREVITY
        success(response: NSString(data: data!, encoding: NSASCIIStringEncoding) as! String)
    }
    loadDataTask.resume()
    }

    // extract data from redirect
    class func getRedirectionInfo(url: String) {
    getDataFromServerWithSuccess(url, noRedirect: true) {(data) -> Void in
        if let html = data {
            if html.rangeOfString("<html>\n<head><title>Bitly</title>", options: .RegularExpressionSearch) != nil {
                print("success: redirection was prevented")
            } else {
                print("failure: redirection went through")
            }
        }
    }
    }
}

MySession.getRedirectionInfo("http://bit.ly/filmenczer")