微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Swift / iOS:发出HTTP GET请求而无需遵循重定向

如何解决Swift / iOS:发出HTTP GET请求而无需遵循重定向

我希望我的Swift iOS应用程序获取通过NSUserActivityTypebrowsingWeb请求接收到的URL。

我的电子邮件服务提供商“包装”链接(就像大多数链接一样),并返回“ 302重定向”消息。我想进行初始GET,以获取“ 302 Found”和“ Location”标头,但我不需要iOS为我关注重定向

添加了以下代码

// Follow the link to trigger click tracking
let task = URLSession.shared.dataTask(with: url) {(data,response,error) in
    guard let data = data else { return }
    print(String(data: data,encoding: .utf8)!)
}
task.resume()

这可行,但是我不需要遵循重定向获取所有数据(因为它可能是一个很大的网页)。

iOS是否提供一种无需遵循重定向即可获取初始HTTP(S)响应的方法? (有点像省略CURL上的--location标志)。

解决方法

您应该使用URLSessionTaskDelegate扩展名实现自定义会话,然后才能在willPerformHTTPRedirection方法内中断重定向:

class Redirect : NSObject {
    var session: URLSession?
    
    override init() {
        super.init()
        session = URLSession(configuration: .default,delegate: self,delegateQueue: nil)
    }
    
    func makeRequest() {
        let url = URL(string: "http://gmail.com")!
        let task = session?.dataTask(with: url) {(data,response,error) in
            guard let data = data else {
                return
            }
            print(String(data: data,encoding: .utf8)!)
        }
        task?.resume()
    }
}

extension Redirect: URLSessionDelegate,URLSessionTaskDelegate {
    func urlSession(_ session: URLSession,task: URLSessionTask,willPerformHTTPRedirection response: HTTPURLResponse,newRequest request: URLRequest,completionHandler: @escaping (URLRequest?) -> Void) {
        // Stops the redirection,and returns (internally) the response body.
        completionHandler(nil)
    }
}

let r = Redirect()
r.makeRequest()

输出:

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/gmail/">here</A>.
</BODY></HTML>
,

感谢iUriikleids我的工作顺利,需要注意几点:

  • 需要回调以从异步任务中获取数据
  • 只能从主队列(!!)更新UILabel,因此需要DispatchQueue.main.async {}
//
//  AppDelegate.swift
//  testlinks
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder,UIApplicationDelegate {
    
    var window: UIWindow?
    
    
    func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }
    
    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks,disable timers,and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources,save user data,invalidate timers,and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution,this method is called instead of applicationWillTerminate: when the user quits.
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }
    
    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background,optionally refresh the user interface.
    }
    
    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
    
    func application(_ application: UIApplication,continue userActivity: NSUserActivity,restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
        // First attempt at handling a universal link
        print("Continue User Activity called: ")
        if userActivity.activityType == NSUserActivityTypeBrowsingWeb,let url = userActivity.webpageURL {
            //handle URL
            let r = Redirect()
            r.makeRequest(url: url,callback: { (location) in
                
                guard let locationURL = location else {return}
                
                print("locationURL",locationURL)
                
                // Show this on our simple example app
                DispatchQueue.main.async {
                    if let vc = self.window?.rootViewController as? ViewController {
                        vc.result.text = url.absoluteString
                        vc.originalURL.text = locationURL.absoluteString
                    }
                    
                }
            })
        }
        return true
    }
}

// More efficient click-tracking with HTTP GET to obtain the "302" response,but not follow the redirect through to the Location.
// The callback is used to return the Location header back from the async task = thanks @kleids
class Redirect : NSObject {
    var session: URLSession?
    
    override init() {
        super.init()
        session = URLSession(configuration: .default,delegateQueue: nil)
    }
    
    func makeRequest(url: URL,callback: @escaping (URL?) -> ()) {
        let task = self.session?.dataTask(with: url) {(data,error) in
            guard response != nil else {
                return
            }
            if let response = response as? HTTPURLResponse {
                if let l = response.value(forHTTPHeaderField: "Location") {
                    callback(URL(string: l))
                }
            }
        }
        task?.resume()
    }
}

extension Redirect: URLSessionDelegate,and returns (internally) the response body.
        completionHandler(nil)
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。