Estoy intentando upload fotos a mi server web a través de AFHTTPRequestOperation
. Aquí está mi AFHTTPSessionManager
. Todas las requestes http a través de este manager
funcionan perfectamente.
- (AFHTTPSessionManager *)manager { if (_manager == nil) { _manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://my.domain.com/api/v2"]]; [_manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"username" password:@"password"]; AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; policy.allowInvalidCertificates = YES; _manager.securityPolicy = policy; } return _manager; }
Pero cuando bash upload fotos con el event handlingl progreso:
- (void)photoSend:(UIImage *)photo toUsers:(NSArray *)users completion:(CompletionHandler)completion progress:(ProgressionHandler)progress { NSDictionary *params = @{ @"token":self.token, @"to_usernames":[users componentsJoinedByString:@","], }; NSString *urlString = [[NSURL URLWithString:@"photo/send" relativeToURL:self.manager.baseURL] absoluteString]; NSMutableURLRequest *request = [self.manager.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:urlString parameters:params constructingBodyWithBlock:^(id <AFMultipartFormData> formData) { [formData appendPartWithFileData:UIImageJPEGRepresentation(photo,0.8) name:@"photo" fileName:@"image.jpg" mimeType:@"image/jpg"]; } error:nil]; AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; operation.responseSerializer = [AFJSONResponseSerializer serializer]; // Following 2 lines does not make sense. Http headers contains auth data without this code //NSURLCnetworkingential *cnetworkingential = [NSURLCnetworkingential cnetworkingentialWithUser:@"login" password:@"password" persistence:NSURLCnetworkingentialPersistenceNone]; //[operation setCnetworkingential:cnetworkingential]; [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { progress(totalBytesWritten*1.0/totalBytesExpectedToWrite); }]; [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { completion(operation.response, responseObject, operation.error); } failure:^(AFHTTPRequestOperation *operation, NSError *error) { completion(operation.response, nil, error); }]; [self.manager.operationQueue addOperation:operation]; }
Obtengo el siguiente error:
Error Domain = NSURLErrorDomain Code = -1012 "La operación no se pudo completar (NSURLErrorDomain error -1012.)" UserInfo = 0x994ff20 {NSErrorFailingURLKey = https://my.domain.com/v2/photo/send , NSErrorFailingURLStringKey = https : // mi.dominio.com/v2/photo/send }
Aquí está la solución:
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; policy.allowInvalidCertificates = YES; operation.securityPolicy = policy;
Por lo tanto, los datos de authentication básicos de HTTP se proporcionan a la operación del administrador, pero la política de SSL no.
En AFNetworking
puede usar AFSSLPinningMode
para realizar cambios en las políticas de security, de modo que si su server no tiene SSL instalado, use el código siguiente
let operation = AFHTTPRequestOperation(request: YourMutableRequestObject) let policy = AFSecurityPolicy(pinningMode: AFSSLPinningMode.None) policy.validatesDomainName = false policy.allowInvalidCertificates = true operation.securityPolicy = policy
Y si su server utiliza un certificate, puede usar el código siguiente
let operation = AFHTTPRequestOperation(request: YourMutableRequestObject) let policy = AFSecurityPolicy(pinningMode: AFSSLPinningMode.Certificate) policy.validatesDomainName = false policy.allowInvalidCertificates = true operation.securityPolicy = policy
Antes de usar el código anterior, asegúrese de haber agregado el certificate cer
en su package de aplicaciones, porque si no lo hace no podrá hacer las llamadas, puede get el file CER de su desarrollador web o de cualquier autoridad que le brinde el cer.
En caso de que si recibe un file crt del desarrollador web, debe convertirlo a cer mediante OpenSSL
utilizando el código siguiente
openssl x509 -in apache.crt -out yourCertFileName.cer -outform der
Eso debería ser suficiente para hacer las llamadas
Actualizar
Según el nuevo patrón ATS de Apple en iOS 9, debes proporcionar algunos permissions dentro de tu file info.plist
.
si quiere hacer una llamada insegura, dar a continuación es el XML que necesita para integrar dentro de info.plist
(tenga en count que no va a get ningún relleno automático aquí, tiene que ver su plist como fuente y copyr + pegar el siguiente)
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>yourserver.com</key> <dict> <!--Include to allow subdomains--> <key>NSIncludesSubdomains</key> <true/> <!--Include to allow HTTP requests--> <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key> <true/> <!--Include to specify minimum TLS version--> <key>NSTemporaryExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> </dict> </dict>
Apple también proporciona una forma de deshabilitar ATS que figura a continuación, es el XML para el mismo, pero no es recomendable
<key>NSAppTransportSecurity</key> <dict> <!--Include to allow all connections --> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
En mi caso, ya que mi server estaba usando un certificate autofirmado, acabo de cambiar el AFSSLPinningMode
a Certificate y funcionó como esperaba.
Espero que esto ayude a alguien