防止 Swift 中的 URLSession 重定向 [英] Preventing URLSession redirect in Swift
问题描述
我需要在 Swift 中获取重定向 URL 但阻止重定向.从其他帖子和 Apple 文档中我了解到我必须实现委托方法 URLSession(session:, task:, willPerformHTTPRedirection response:, request:, completionHandler:)
并通过返回 nil
完成关闭.但是我无法快速找到示例,也找不到正确的方法.下面的代码在操场上重现了我的问题:委托似乎没有被执行.
I need to fetch a redirecting URL but prevent redirection in Swift. From other posts and Apple docs I understand I must implement the delegate method URLSession(session:, task:, willPerformHTTPRedirection response:, request:, completionHandler:)
and return nil
via the completion closure. But I can't find examples in swift, nor figure out the right way to do it. The code below reproduces my issue in playground: the delegate does not seem to get executed.
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
作为委托传递会产生习惯行为(带有重定向).这是代码的工作版本:
UPDATE: With many thanks to @nate I got it to work. The key insight is that in order for the delegate to be called, one must pass the delegate class to the NSURLSession()
initializer, rather than using NSURLSession.sharedSession()
. Passing nil
as the delegate yields the customary behavior (with redirection). Here is working version of the code:
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")
推荐答案
有两件事情阻碍了您当前的实施.
You have two things standing in your way with your current implementation.
您从未在用于发出请求的
NSURLSession
实例上设置委托属性.如果没有设置委托属性,您的委托方法将永远不会被调用.与其获取NSURLSession.sharedSession()
,不如查看NSURLSession(configuration:delegate:delegateQueue:)
初始值设定项.第一个和最后一个参数可以分别是NSURLSessionConfiguration.defaultSessionConfiguration()
和nil
,有关委托的更多信息,请参见下文.
You never set the delegate property on the
NSURLSession
instance that you're using to make the request. Without the delegate property set, your delegate methods won't ever be called. Instead of gettingNSURLSession.sharedSession()
, look at theNSURLSession(configuration:delegate:delegateQueue:)
initializer. The first and last parameters can beNSURLSessionConfiguration.defaultSessionConfiguration()
andnil
, respectively, see below for more about the delegate.
请注意,当您使用具有完成处理程序的 session.dataTaskWithURL
变体时,处理响应和数据传递的委托方法将被忽略,但仍会使用身份验证和重定向处理程序.>
Note that when you use the variant of
session.dataTaskWithURL
that has a completion handler, delegate methods that handle response and data delivery will be ignored, but authentication and redirection handlers are still used.
您必须进行一些重构才能使用 MySession
作为委托,因为您使用类方法来发出请求.您需要一个实例作为会话的委托.
You'll have to refactor somewhat to use MySession
as a delegate, since you're using class methods to make the request. You need an instance to use as the session's delegate.
我采用了一条简短且不完整的路线,让委托使用此替代代码进行重定向——您需要像 #3 中那样重构以确保您仍然可以调用您的回调:
I took a short and incomplete route to having the delegate pick up on the redirect with this alternate code—you'll need to refactor as in #3 to make sure you can still call your callback:
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 中的 URLSession 重定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!