在Swift中防止URLSession重定向

时间:2015-03-16 05:56:51

标签: ios swift redirect

我需要在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,我得到了它的工作。关键的见解是,为了调用委托,必须将委托类传递给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")

3 个答案:

答案 0 :(得分:4)

您目前的实施方式阻碍了两件事。

  1. 您永远不会在您用于发出请求的NSURLSession实例上设置委托属性。如果没有委托属性集,您的委托方法将永远不会被调用。不要获取NSURLSession.sharedSession(),而是查看NSURLSession(configuration:delegate:delegateQueue:)初始值设定项。第一个和最后一个参数可分别为NSURLSessionConfiguration.defaultSessionConfiguration()nil,有关代理的详情,请参阅下文。

      

    请注意,当您使用具有完成处理程序的session.dataTaskWithURL变体时,将忽略处理响应和数据传递的委托方法,但仍会使用身份验证和重定向处理程序。

  2. 由于您正在使用类方法发出请求,因此您必须稍微重构以使用MySession作为委托。您需要一个实例用作会话的代理。

  3. 我采用了一条简短且不完整的路线,让代理人使用此备用代码接收重定向 - 您需要像#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()
    }
    

    希望有所帮助!

答案 1 :(得分:1)

对上述解决方案进行微调。这适用于XCode 7中的Swift 2。

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

答案 2 :(得分:0)

我也发现该解决方案很有帮助,但是我在当前项目中使用的是Swift 4.2。

因此,这是上述解决方案的经过改编的简短版本,也可以与 Swift 4.2 Xcode 10 一起使用。

pip install firebase