简体   繁体   English

如何在 Alamofire 4 和 Swift 3 中使用代理服务器

[英]How to use a Proxy Server with Alamofire 4 and Swift 3

Please don't mark as duplicate, I haven't been able to solve my Issue with the existing threads.请不要标记为重复,我无法用现有线程解决我的问题。

I'm trying to use my Proxy for an API request that needs a specified IP.我正在尝试将我的代理用于需要指定 IP 的 API 请求。 To debug my issue, I'm requesting the IP from a webservice.为了调试我的问题,我从网络服务请求 IP。

This is my current code:这是我当前的代码:

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

The problem: the responsed IP is the same with or without the proxyConfiguration .问题:无论有没有proxyConfiguration ,响应的 IP 都是相同的。 Any help is very appreciated.非常感谢任何帮助。

PS: physical device used. PS:使用的物理设备。

I think the working (supposed to be deprecated) keys are:我认为工作(应该被弃用)键是:

kCFStreamPropertyHTTPSProxyHost
kCFStreamPropertyHTTPSProxyPort

Could you try this code?你能试试这个代码吗?

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

Also please make sure your proxy server is configured to handle https requests.另外请确保您的代理服务器配置为处理 https 请求。

Note: It might give deprecated warning for those keys but keys are still working (see https://forums.developer.apple.com/thread/19356#131446 )注意:它可能会为这些键提供deprecated警告,但键仍在工作(请参阅https://forums.developer.apple.com/thread/19356#131446

Note: I posted the same answer here .注意:我在这里发布了相同的答案。 Posting the same here as it was applicable here as well.在此处发布相同的内容,因为它也适用于此处。 Alamofire is using same URLSessionConfiguration . Alamofire 使用相同的URLSessionConfiguration

Based off Manishg's answer I use the following to avoid warnings根据 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)

The https constants have been deprecated and could be removed at anytime. https 常量已被弃用,可以随时删除。 By using the string values, the code might break but it won't crash通过使用字符串值,代码可能会中断但不会崩溃

Base on Fraser answer and How can I get my external IP address in a shell script?基于Fraser 的回答以及如何在 shell 脚本中获取我的外部 IP 地址? question

Details细节

  • Swift 5.3斯威夫特 5.3
  • Version 12.4 (12D4e)版本 12.4 (12D4e)
  • Alamofire 5阿拉莫火 5

Full Sample完整样本

NetworkService.swift网络服务.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 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视图控制器.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)
    }
}

Screenshots截图

在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM