【问题标题】:How to use a Proxy Server with Alamofire 4 and Swift 3如何在 Alamofire 4 和 Swift 3 中使用代理服务器
【发布时间】:2017-07-25 19:23:59
【问题描述】:

我正在尝试将我的代理用于需要指定 IP 的 API 请求。 为了调试我的问题,我从网络服务请求 IP。

这是我当前的代码:

import UIKit
import Alamofire

class ViewController: UIViewController {

    var requestManager = Alamofire.SessionManager.default
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(true)
        
        var proxyConfiguration = [NSObject: AnyObject]()
        proxyConfiguration[kCFNetworkProxiesHTTPProxy] = "http://xxx@eu-west-static-01.quotaguard.com" as AnyObject?
        proxyConfiguration[kCFNetworkProxiesHTTPPort] = "9293" as AnyObject?
        proxyConfiguration[kCFNetworkProxiesHTTPEnable] = 1 as AnyObject?
        
        let cfg = Alamofire.SessionManager.default.session.configuration
        cfg.connectionProxyDictionary = proxyConfiguration

        let ip = URL(string: "https://api.ipify.org?format=json")
        
        requestManager = Alamofire.SessionManager(configuration: cfg)
        requestManager.request(ip!).response { response in
            print("Request: \(response.request)")
            print("Response: \(response.response)")
            print("Error: \(response.error)")
            
            if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
                print("Data: \(utf8Text)")
            }
        }
    }
}

问题:无论有没有proxyConfiguration,响应的IP都是一样的。

PS:使用的物理设备。

【问题讨论】:

    标签: ios swift alamofire


    【解决方案1】:

    基于Fraser 答案和How can I get my external IP address in a shell script? 问题

    详情

    • 斯威夫特 5.3
    • 版本 12.4 (12D4e)
    • 阿拉莫菲尔 5

    完整样本

    NetworkService.swift

    import Foundation
    import Alamofire
    
    struct Proxy {
        let host: String
        let port: Int
    }
    
    class NetworkService {
        
        // Pick free some proxies from here https://free-proxy-list.net if current do not work
        private let listOfProxies = [
            Proxy(host: "67.43.224.131", port: 3128), // Canada
            Proxy(host: "167.172.180.40", port: 44129), // Germany
            Proxy(host: "185.236.202.205", port: 3128), // Austria
        ]
        
        private(set) var session: Session!
        private var proxy: Proxy?
        init () { resetSessionManager() }
    
        func setRandomProxy() {
            self.proxy = listOfProxies.randomElement()
            resetSessionManager()
        }
    
        private
        func resetSessionManager() {
            let config = Session.default.session.configuration
            if let proxy = proxy {
                config.connectionProxyDictionary = [
                    "HTTPEnable": 1,
                    "HTTPProxy": proxy.host ,
                    "HTTPPort": proxy.port,
                    "HTTPSEnable": true,
                    "HTTPSProxy": proxy.host,
                    "HTTPSPort": proxy.port
                ]
            } else {
                config.connectionProxyDictionary = [:]
            }
            self.session = Session(configuration: config)
        }
        
        func request(url: URLConvertible,
                     method: Alamofire.HTTPMethod = .get,
                     parameters: Parameters? = nil,
                     encoding: ParameterEncoding = URLEncoding.default,
                     headers: HTTPHeaders? = nil,
                     completion: @escaping (Result<Data, Error>) -> Void) {
            let request = session.request(url, method: method,
                                          parameters: parameters,
                                          encoding: encoding,
                                          headers: headers)
            request.response { respionse in
                if let error = respionse.error {
                    completion(.failure(error))
                } else if let data = respionse.data {
                    completion(.success(data))
                }
            }
        }
        func request<T: Decodable>(url: URLConvertible,
                                   method: Alamofire.HTTPMethod = .get,
                                   parameters: Parameters? = nil,
                                   encoding: ParameterEncoding = URLEncoding.default,
                                   headers: HTTPHeaders? = nil,
                                   completion: @escaping (Result<T, Error>) -> Void) {
            request(url: url, method: method,
                    parameters: parameters,
                    encoding: encoding,
                    headers: headers) { result in
                switch result {
                case .failure(let error): completion(.failure(error))
                case .success(let data):
                    do {
                        let object = try JSONDecoder().decode(T.self, from: data)
                        completion(.success(object))
                    } catch let error {
                        completion(.failure(error))
                    }
                }
            }
        }
    }
    

    GeoIP.swift

    import Foundation
    
    struct GeoIP: Codable {
        let lat: Double
        let lon: Double
        let zip: String
        let query: String
        let city: String
        let regionName: String
        let country: String
        let timezone: String
    }
    
    extension GeoIP: CustomStringConvertible {
        var description: String {
            "\(city), \(regionName), \(country), \(zip)\nIP:\(query)\nCoordinates:(\(lat),\(lon))\nTimezone: \(timezone)"
        }
    }
    

    ViewController.swift

    class ViewController: UIViewController {
        
        private let networkService = NetworkService()
        private weak var button: UIButton!
        private weak var activityIndicatorView: UIActivityIndicatorView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            let button = UIButton(frame: view.frame)
            button.setTitleColor(.blue, for: .normal)
            button.setTitle("Pick random proxy and get my ip", for: .normal)
            button.addTarget(self, action: #selector(buttonTouchedUpInside(source:)), for: .touchUpInside)
            view.addSubview(button)
            self.button = button
            
            let activityIndicatorView = UIActivityIndicatorView(frame: view.frame)
            view.addSubview(activityIndicatorView)
            self.activityIndicatorView = activityIndicatorView
        }
        
        @objc func buttonTouchedUpInside(source: UIButton) {
            source.isHidden = true
            activityIndicatorView.startAnimating()
            networkService.setRandomProxy()
            showMyGeoIpInfo()
        }
    }
    
    extension ViewController {
        
        private func showMyGeoIpInfo() {
            let group = DispatchGroup()
            group.enter()
            group.enter()
            group.enter()
            var httpIP: String?
            var httpsIP: String?
            var geoIp: GeoIP?
            group.notify(queue: .main) { [weak self] in
                guard let self = self else { return }
                let _httpIP = httpIP ?? "nil"
                let _httpsIP = httpsIP ?? "nil"
                let geoIpDescription = geoIp?.description ?? "nil"
                let message = "HTTP request IP: \(_httpIP)\nHTTPS request IP: \(_httpsIP)\n GeoIP: \(geoIpDescription)"
                self.showAlert(title: "GeoIP", message: message)
                self.button.isHidden = false
                self.activityIndicatorView.stopAnimating()
            }
            
            // Get my IP on http request
            getSimpleText(from: "http://ipecho.net/plain") { text in
                httpIP = text
                group.leave()
            }
            
            // Get my IP on https request
            getSimpleText(from: "https://icanhazip.com") { text in
                httpsIP = text
                group.leave()
            }
            
    
            // Get my GeoIp info
            networkService.request(url: "http://ip-api.com/json/",
                                   encoding: JSONEncoding.default) { (response: Result<GeoIP, Error>) in
                defer { group.leave() }
                switch response {
                case .failure(let error): print("Error: \(error)")
                case .success(let value): geoIp = value
                }
            }
        }
        
        private func getSimpleText(from url: String, completion: @escaping (String?) -> Void) {
            networkService.request(url: "https://icanhazip.com") { result in
                switch result {
                case .failure(let error):
                    print("Error: \(error)")
                    completion(nil)
                case .success(let data):
                    let text = String(decoding: data, as: UTF8.self).trimmingCharacters(in: .whitespacesAndNewlines)
                    completion(text)
                }
            }
        }
    
        private func showAlert(title: String?, message: String?) {
            let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
            alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
            present(alertController, animated: true, completion: nil)
        }
    }
    

    截图

    【讨论】:

      【解决方案2】:

      根据 Manishg 的回答,我使用以下内容来避免警告

      let configuration = URLSessionConfiguration.default
      configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
      
      var proxyConfiguration = [String: AnyObject]()
      proxyConfiguration.updateValue(1 as AnyObject, forKey: "HTTPEnable")
      proxyConfiguration.updateValue("eu-west-static-01.quotaguard.com" as AnyObject, forKey: "HTTPProxy")
      proxyConfiguration.updateValue(9293 as AnyObject, forKey: "HTTPPort")
      proxyConfiguration.updateValue(1 as AnyObject, forKey: "HTTPSEnable")
      proxyConfiguration.updateValue("eu-west-static-01.quotaguard.com" as AnyObject, forKey: "HTTPSProxy")
      proxyConfiguration.updateValue(9293 as AnyObject, forKey: "HTTPSPort")
      configuration.connectionProxyDictionary = proxyConfiguration
      
      sharedManager = Alamofire.SessionManager(configuration: configuration)
      

      https 常量已被弃用,可以随时删除。通过使用字符串值,代码可能会中断但不会崩溃

      【讨论】:

        【解决方案3】:

        我认为有效的(应该被弃用的)键是:

        kCFStreamPropertyHTTPSProxyHost
        kCFStreamPropertyHTTPSProxyPort
        

        你能试试这个代码吗?

        import UIKit
        import Alamofire
        
        class ViewController: UIViewController {
        
            var requestManager = Alamofire.SessionManager.default
        
            override func viewDidLoad() {
                super.viewDidLoad()
            }
        
            override func viewDidAppear(_ animated: Bool) {
                super.viewDidAppear(true)
        
                 var proxyConfiguration = [NSObject: AnyObject]()
                 proxyConfiguration[kCFNetworkProxiesHTTPProxy] = "eu-west-static-01.quotaguard.com" as AnyObject?
                 proxyConfiguration[kCFNetworkProxiesHTTPPort] = "9293" as AnyObject?
                 proxyConfiguration[kCFNetworkProxiesHTTPEnable] = 1 as AnyObject?
                 proxyConfiguration[kCFStreamPropertyHTTPSProxyHost as String] = "eu-west-static-01.quotaguard.com"
                 proxyConfiguration[kCFStreamPropertyHTTPSProxyPort as String] = 9293
                 proxyConfiguration[kCFProxyUsernameKey as String] = xxx
                 //proxyConfiguration[kCFProxyPasswordKey as String] = "pwd if any"
                let cfg = Alamofire.SessionManager.default.session.configuration
                cfg.connectionProxyDictionary = proxyConfiguration
        
                let ip = URL(string: "https://api.ipify.org?format=json")
        
                requestManager = Alamofire.SessionManager(configuration: cfg)
                requestManager.request(ip!).response { response in
                    print("Request: \(response.request)")
                    print("Response: \(response.response)")
                    print("Error: \(response.error)")
        
                    if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
                        print("Data: \(utf8Text)")
                    }
                }
            }
        }
        

        另外请确保您的代理服务器已配置为处理 https 请求。

        注意:它可能会为这些键发出 deprecated 警告,但键仍在工作(请参阅 https://forums.developer.apple.com/thread/19356#131446

        注意:我发布了相同的答案here。在此处发布与此处也适用的内容相同的内容。 Alamofire 使用相同的URLSessionConfiguration

        【讨论】:

        • 添加了用户名和密码的属性键。我认为这些也将是使其工作所必需的。
        猜你喜欢
        • 2017-03-31
        • 2017-05-26
        • 1970-01-01
        • 2018-01-19
        • 1970-01-01
        • 2023-03-14
        • 2018-02-18
        • 1970-01-01
        • 2020-12-02
        相关资源
        最近更新 更多