如何以编程方式向NSURLSession添加代理

12

浏览了 NSURLSessionNSURLSessionConfiguration 的文档之后,我认为我应该使用如下的字典进行配置:

    // Create a dictionary to describe the proxy 
    NSDictionary *proxyDict = @{
        (NSString *)kCFProxyHostNameKey   : @"myProxyHost.com",
        (NSString *)kCFProxyPortNumberKey : @"12345",
        (NSString *)kCFProxyTypeKey       : (NSString*)kCFProxyTypeHTTP
    };

    // Create a configuration that uses the dictionary
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    [configuration setConnectionProxyDictionary:proxyDict];

但是,使用此配置创建的NSURLSession请求将直接连接。

6个回答

24

事实证明,您想要的字典键是Stream变体,它们会解析为"HTTPProxy"等内容:

NSString* proxyHost = @"myProxyHost.com";
NSNumber* proxyPort = [NSNumber numberWithInt: 12345];

// Create an NSURLSessionConfiguration that uses the proxy
NSDictionary *proxyDict = @{
    @"HTTPEnable"  : [NSNumber numberWithInt:1],
    (NSString *)kCFStreamPropertyHTTPProxyHost  : proxyHost,
    (NSString *)kCFStreamPropertyHTTPProxyPort  : proxyPort,

    @"HTTPSEnable" : [NSNumber numberWithInt:1],
    (NSString *)kCFStreamPropertyHTTPSProxyHost : proxyHost,
    (NSString *)kCFStreamPropertyHTTPSProxyPort : proxyPort,
};

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
configuration.connectionProxyDictionary = proxyDict;

// Create a NSURLSession with our proxy aware configuration
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];

// Form the request
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.com?2"]];

// Dispatch the request on our custom configured session
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:
                              ^(NSData *data, NSURLResponse *response, NSError *error) {
                                  NSLog(@"NSURLSession got the response [%@]", response);
                                  NSLog(@"NSURLSession got the data [%@]", data);
                              }];

NSLog(@"Lets fire up the task!");
[task resume];

谢谢!谢谢一百万次!我永远也想不到这个。如果苹果能记录下来就太好了。 - bugloaf
@Jeff - 我已经尝试过了,但是从 ^(NSData *data, NSURLResponse *response, NSError *error) 返回的数据给出的是 myProxyHost.com 的结果,而不是 www.google.com。你能帮我吗? - Balaji Kondalrayal
可以使用用户名/密码吗?如果可以,如何实现? - Alexander Yatsenko
1
@AlexanderYatsenko 当我在2015年进行这项研究时,答案是坚定的“否”,这相当令人恼火,因为我碰巧知道用户很快会被提示输入凭据。问题在于苹果处理代理挑战的方式是在其自己的层面上进行处理,并且不向您公开任何API。请参见用于身份验证挑战的委托,它明确避免了代理身份验证。(也许这是由于存在链接代理的存在。) - Jeff
如果我有一个包含自动代理配置的PAC文件,我可以在某个地方设置这个PAC文件吗?(在这个文件中,我已经定义了一些服务器应该通过代理访问,其他服务器应该直接访问)这是可能的吗? - nacho4d

9
如果有人需要Swift版本,请参考以下内容:
Swift 3
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable as AnyHashable: true,
    kCFNetworkProxiesHTTPPort as AnyHashable: 999, //myPortInt
    kCFNetworkProxiesHTTPProxy as AnyHashable: "myProxyUrlString"
]
let session = URLSession(configuration: sessionConfiguration)

我在使用中遇到麻烦。即使使用代理,我的 API 请求的 IP 与未使用代理时相同... - David Seek
https://dev59.com/vlgQ5IYBdhLWcg3wikaT - David Seek
你如何在UIWebView或URLSession上使用会话(session)? - user2924482

9
由于Jeff的一些答案键已被弃用,因此我使用这些答案键。
NSMutableDictionary *proxy=[NSMutableDictionary dictionaryWithDictionary:@{(__bridge NSString *)kCFNetworkProxiesHTTPEnable  : @1,  (__bridge NSString *)kCFNetworkProxiesHTTPSEnable : @1}];
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPProxy] =host;
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPSProxy]=host;
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPPort]  =port;
proxy[(__bridge NSString *)kCFNetworkProxiesHTTPSPort] =port;
proxy[(__bridge NSString *)kCFProxyUsernameKey]=user;
proxy[(__bridge NSString *)kCFProxyPasswordKey]=password;

configuration.connectionProxyDictionary=proxy;

4

kCFProxyPortNumberKey 的值应该是 Int 类型而不是 String 类型。


3

根据之前的所有回复,这适用于Swift 4,HTTP和HTTPS:

let proxyHost = "127.0.0.1"
let proxyPort = 8888
let configuration = URLSessionConfiguration.default
configuration.connectionProxyDictionary = [
    kCFNetworkProxiesHTTPEnable: true,
    kCFNetworkProxiesHTTPProxy: proxyHost,
    kCFNetworkProxiesHTTPPort: proxyPort,
    kCFNetworkProxiesHTTPSEnable: true,
    kCFNetworkProxiesHTTPSProxy: proxyHost,
    kCFNetworkProxiesHTTPSPort: proxyPort
]

proxyHost 应该是一个主机名,不包含任何 URL 方案。


3

Swift 3 extension

extension URLSession {

    func withProxy(proxyURL: String, proxyPort: Int) -> URLSession {

        var configuration = self.configuration

        configuration.connectionProxyDictionary = [
            kCFNetworkProxiesHTTPEnable as AnyHashable : true,
            kCFNetworkProxiesHTTPPort as AnyHashable : proxyPort,
            kCFNetworkProxiesHTTPProxy as AnyHashable : proxyURL
        ]

        return URLSession(configuration: configuration, delegate: self.delegate, delegateQueue: self.delegateQueue)
    }
}

使用方法:

let session = URLSession().withProxy(proxyURL: "xxxxxx", proxyPort: 8321)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接