LoginSignup
4
4

More than 5 years have passed since last update.

AFNetworking 2.xでプロキシを使う

Last updated at Posted at 2015-06-02

はじめに

概要

  • はじめに、NSURLSessionでのプロキシ通信の実装例を示します
  • つぎに、AFNetworking 2.xでのプロキシ通信の実装例を示します
  • 最後に、補足としてPACファイルからプロキシ設定を取得する実装例を示します
  • 実装例は、Mac OS X Yosemite 10.10.3で動作確認しています

AFNetworkingの補足

  • AFNetworking 1.xではNSURLConnectionを使っており、NSURLConnectionはプロキシをサポートしていないため、CFNetwork系のAPIを使って独自に実装する必要があるようです
  • 一方、AFNetworking 2.xではNSURLSessionを使え、NSURLSessionNSURLSessionConfiguration.connectionProxyDictionaryでプロキシを指定できます
  • 参考: ios - how to set proxy details using AFNetworking - Stack Overflow

こちらも参照してください

注意

(NSURLSession) プロキシ通信の実装例

  • NSURLSessionNSURLSessionDataTaskを直接使用する場合の実装例です
  • 実行環境: OS X Yosemite 10.10.3
  • Xcode 6.3.2

- (IBAction)proxyConnectAction:(id)sender {  
//  NSDictionary *httpProxy = @{(id)kCFNetworkProxiesHTTPEnable:  @(1),
//                            (id)kCFStreamPropertyHTTPProxyHost: host,
//                            (id)kCFStreamPropertyHTTPProxyPort: port};

  // 注意: iOSでは`HTTPS`のkeyが定義されていません
  NSDictionary *httpsProxy = @{(id)kCFNetworkProxiesHTTPSEnable:    @(1),
                               (id)kCFStreamPropertyHTTPSProxyHost: @"127.0.0.1",
                               (id)kCFStreamPropertyHTTPSProxyPort: @(8888)};

  NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
  configuration.connectionProxyDictionary = httpsProxy;
  NSURL *url = [NSURL URLWithString:@"https://www.example.com/foobar.png"];
  NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
  NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSLog(@"response: %@", response);
    NSLog(@"data length: %ld", data.length);
    if (error) {
      NSLog(@"error:%@", error);
    }
  }];
  [dataTask resume];
}

(AFNetworking 2.x) プロキシ通信の実装例

  • AFNetworkingのAFHTTPSessionManagerを使用する場合の実装例です
  • 実行環境: OS X Yosemite 10.10.3
  • Xcode 6.3.2
  • AFNetworking 2.5.4

RestClientの例

RestClient.h
#import <Foundation/Foundation.h>

@interface RestClient : NSObject
@property (copy, nonatomic) NSURL *baseURL;
@property (copy, nonatomic) NSDictionary *proxyDictionary;
@property (nonatomic) BOOL allowInvalidCertificates; // For debugging (Default: NO)

- (instancetype)initWithBaseURL:(NSURL *)baseURL;
- (instancetype)initWithBaseURL:(NSURL *)baseURL proxyDictionary:(NSDictionary *)proxyDictionary;

- (void)getWithPath:(NSString *)path
         parameters:(NSDictionary *)parameters
            success:(void (^)(id responseObject))success
            failure:(void (^)(NSError *error))failure;

@end
  • initWithBaseURL:sessionConfiguration:を使って、AFHTTPSessionManagerを作成します
  • NSURLSessionConfiguration.connectionProxyDictionaryに、プロキシの情報を入れたNSDictionaryを指定します
RestClient.m
#import "RestClient.h"
#import <AFNetworking/AFNetworking.h>

@interface RestClient ()
@property (strong) AFHTTPSessionManager *httpSessionManager;

@end

@implementation RestClient

- (instancetype)initWithBaseURL:(NSURL *)baseURL {
  self = [super init];
  if (!self) {
    return nil;
  }

  self.baseURL = baseURL;

  return self;
}

- (instancetype)initWithBaseURL:(NSURL *)baseURL proxyDictionary:(NSDictionary *)proxyDictionary {
  self = [self initWithBaseURL:baseURL];
  if (!self) {
    return nil;
  }

  self.proxyDictionary = proxyDictionary;

  return self;
}

- (AFHTTPSessionManager *)_sessionManager {
  AFHTTPSessionManager *manager = self.httpSessionManager;

  if (!manager) {
    // Configure AFHTTPSessionManager
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfig.connectionProxyDictionary = self.proxyDictionary;

    manager = [[AFHTTPSessionManager alloc] initWithBaseURL:self.baseURL sessionConfiguration:sessionConfig];
    manager.securityPolicy.allowInvalidCertificates = self.allowInvalidCertificates;

    // Set Serializer
    manager.requestSerializer  = [AFJSONRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];

    // Configure JSON Request Serializer
    manager.requestSerializer.timeoutInterval = 20.0f;
    manager.requestSerializer.cachePolicy     = NSURLRequestReloadIgnoringCacheData;

    // Set default header to requestSerializer
    [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"content-type"];

    // Configure JSON Response Serializer
    ((AFJSONResponseSerializer *)(manager.responseSerializer)).readingOptions |= NSJSONReadingAllowFragments;
    self.httpSessionManager = manager;
  }

  return manager;
}

- (void)getWithPath:(NSString *)path
         parameters:(NSDictionary *)parameters
            success:(void (^)(id responseObject))success
            failure:(void (^)(NSError *error))failure {
  AFHTTPSessionManager *manager = [self _sessionManager];
  manager.responseSerializer = [AFHTTPResponseSerializer serializer];
  [manager GET:path parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) {
    NSLog(@"task:%@", task);
    success(responseObject);
  } failure:^(NSURLSessionDataTask *task, NSError *error) {
    NSLog(@"task:%@", task);
    failure(error);
  }];
}

@end

RestClientを使う側

Example.m

// [proxy] https://127.0.0.1:8888
NSDictionary *httpsProxy = @{(id)kCFNetworkProxiesHTTPSEnable:    @(1),
                             (id)kCFStreamPropertyHTTPSProxyHost: @"127.0.0.1",
                             (id)kCFStreamPropertyHTTPSProxyPort: @(8888)};

NSURL *baseURL = [self _baseURL];
NSString *path = [self _path];

RestClient *client = [[RestClient alloc] initWithBaseURL:baseURL proxyDictionary:httpsProxy];
[client getWithPath:path parameters:nil success:^(id responseObject) {
  NSData *data = (NSData *)responseObject;
  NSImage *image = [[NSImage alloc] initWithData:data];
  self.imageView.image = image;
} failure:^(NSError *error) {
  NSLog(@"error: %@", error);
  self.imageView.image = nil;
}];

(補足) PACファイルからプロキシ設定を取得する

システム環境設定

  • システム環境設定ネットワーク任意のアダプタプロキシでPACファイルを指定した場合

Proxy Settings

実装例

  • 実行環境: OS X Yosemite 10.10.3
  • Xcode 6.3.2
  • CoreFoundationのCFNetworkCopyProxiesForAutoConfigurationScript()使うと、これから接続するURLに該当するプロキシの情報を取得できます

- (void)_proxiesWithPACScriptURL:(NSURL *)pacScriptURL intendedURL:(NSURL *)intendedURL {
  if (!pacScriptURL || !intendedURL) {
    return;
  }

  NSError *error = nil;
  NSString *script;

  script = [NSString stringWithContentsOfURL:pacScriptURL usedEncoding:NULL error:&error];
  if (error) {
    NSLog(@"error: %@", error);
    return;
  }

  CFErrorRef cfErrorRef = NULL;
  NSArray *proxies = (__bridge NSArray *)CFNetworkCopyProxiesForAutoConfigurationScript((__bridge CFStringRef)script, (__bridge CFURLRef)intendedURL, &cfErrorRef);
  if (cfErrorRef || !proxies.count) {
    NSError *error = (__bridge NSError *)cfErrorRef;
    NSLog(@"error: %@", error);
    return;
  }

  NSLog(@"proxies: %@", proxies);
}

- (IBAction)getProxyInfoAction:(id)sender {
  CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL);
  NSDictionary *config = (__bridge NSDictionary *)proxies;

  NSLog(@"______________________");
  NSLog(@"kSCPropNetProxiesProxyAutoDiscoveryEnable: %@", config[(id)kSCPropNetProxiesProxyAutoDiscoveryEnable]);
  NSLog(@"kSCPropNetProxiesProxyAutoConfigEnable   : %@", config[(id)kSCPropNetProxiesProxyAutoConfigEnable]);
  NSLog(@"kSCPropNetProxiesProxyAutoConfigURLString: %@", config[(id)kSCPropNetProxiesProxyAutoConfigURLString]);

  NSLog(@"kSCPropNetProxiesHTTPEnable  : %@", config[(id)kSCPropNetProxiesHTTPEnable]);
  NSLog(@"kSCPropNetProxiesHTTPPort    : %@", config[(id)kSCPropNetProxiesHTTPPort]);
  NSLog(@"kSCPropNetProxiesHTTPSEnable : %@", config[(id)kSCPropNetProxiesHTTPSEnable]);
  NSLog(@"kSCPropNetProxiesHTTPSPort   : %@", config[(id)kSCPropNetProxiesHTTPSPort]);
  NSLog(@"______________________");

  NSURL *pacScriptURL = [NSURL URLWithString:config[(id)kSCPropNetProxiesProxyAutoConfigURLString]];
  if (pacScriptURL) {
    NSURL *intendedURL = [NSURL URLWithString:@"https://www.apple.com"];
    [self _proxiesWithPACScriptURL:pacScriptURL intendedURL:intendedURL];
  }
}

PACファイルの例

function FindProxyForURL(url, host) {
  if ( isInNet( host, "127.0.0.1", "255.255.255.255" )) {
    return "DIRECT";
  }
  else if ( dnsDomainIs( host, "beta.example.com") ) {
    return "PROXY 127.0.0.1:8888"
  }
  else {
    return "PROXY 127.0.0.1:8888"
  }
}

実行結果

ProxyInfo[71363:4147289] ______________________
ProxyInfo[71363:4147289] kSCPropNetProxiesProxyAutoDiscoveryEnable: (null)
ProxyInfo[71363:4147289] kSCPropNetProxiesProxyAutoConfigEnable   : 1
ProxyInfo[71363:4147289] kSCPropNetProxiesProxyAutoConfigURLString: http://localhost:4567/proxy4.pac
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPEnable  : 0
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPPort    : (null)
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPSEnable : 0
ProxyInfo[71363:4147289] kSCPropNetProxiesHTTPSPort   : (null)
ProxyInfo[71363:4147289] ______________________
ProxyInfo[71363:4147289] proxies: (
        {
        kCFProxyHostNameKey = "127.0.0.1";
        kCFProxyPortNumberKey = 8888;
        kCFProxyTypeKey = kCFProxyTypeHTTPS;
    }
)

参照

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4