2011-01-06 2 views
19

Qualcuno può dirmi come posso effettuare una chiamata sincrona al server https? Sono in grado di fare una richiesta asincrona sul server https usando i seguenti metodi delegati.Richiesta sincrona NSURLConnection su https

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace 

e

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 

ma ho bisogno di fare sincrona.

risposta

13
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error 

in NSUrlConnection dovrebbe funzionare bene con https.

Se si desidera fornire credenziali, devono essere parte dell'URL: (https://username:[email protected]/api/user.json).

Non c'è modo di fornire un delegato NSURLConnection, quindi se avete bisogno di una gestione di autenticazione non standard dovrete farlo in modo asincrono.

+0

Il ragazzo ha bisogno di una chiamata di funzione dipendente dall'istanza per fornire al delegato la risposta alla sfida https – LolaRun

+0

Grazie :) È così semplice. –

24

// Codifica richiesta

NSData *postData = [xmlText dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 

**//Calculating length of request** 
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]]; 

NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; 
[request setURL:[NSURL URLWithString:requestUrlString]]; 
[request setHTTPMethod:@"POST"]; 
[request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 
[request setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"]; 
[request setHTTPBody:postData]; 
NSURLResponse* response; 
NSError* error = nil; 

//Capturing server response 
NSData* result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 
+2

L'uso di NSUTF8StringEncoding dovrebbe essere preferito se ci sono dati che supportano anche caratteri internazionali, ad esempio: tedesco, italiano, ecc. Altrimenti il ​​metodo di cui sopra è assolutamente perfetto .. –

+0

Non dimenticare le emoticon, hanno bisogno anche di UTF8) –

+0

Il ragazzo ha bisogno di una chiamata di funzione dipendente dall'istanza per fornire al delegato di rispondere alla sfida https – LolaRun

6

Ecco come ho fatto: invece di

[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error] 

ho fatto la stessa istanza metodo basato sulla classe che contiene, dal momento che ci sarà ho bisogno di un delegato. E non renderlo singleton, quindi ogni connessione ha le sue variabili indipendenti, perché, se non lo facciamo, e due connessioni vengono chiamate prima che l'altra termini, quindi i dati ricevuti e la gestione dei loop verranno intrecciati irrecuperabilmente .

[[ClassNameHere new] sendSynchronousRequest:request returningResponse:&response error:&error] 

in questo modo posso creare una connessione NSUrl e gestire la cosa (in modo sincrono, vedremo come) in modo da non dover modificare qualsiasi del codice scritto in precedenza.

- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse *__strong*)response error:(NSError *__strong*)error 
{ 
    _finishedLoading=NO; 
    _receivedData=[NSMutableData new]; 
    _error=error; 
    _response=response; 

    NSURLConnection*con=[NSURLConnection connectionWithRequest:request delegate:self]; 
    [con start]; 
    CFRunLoopRun(); 

    return _receivedData; 
} 


- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { 
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
{ 
    //handle the challenge 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    *_response=response; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [_receivedData appendData:data]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    *_error=error; 
    CFRunLoopStop(CFRunLoopGetCurrent()); 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    CFRunLoopStop(CFRunLoopGetCurrent()); 
} 

Il trucco era in CFRunLoopRun() e CFRunLoopStop (CFRunLoopGetCurrent()) Spero che aiuta qualcun altro in futur.

+2

Non chiederò perché si dovrebbe rispondere a una domanda di 250 anni, e specialmente quella;) Ma, cosa più importante, vorrei per dire che il tuo codice non si autentica correttamente e non è sicuro. Quindi, se questo è solo un codice di prova per sbarazzarsi dei certificati, questo è OK. Per la produzione, è un rischio per la sicurezza. – CouchDeveloper

+0

Qui ho dovuto affrontare lo stesso problema che ha avuto, ho dovuto connettermi a un https più avanti nello sviluppo. E ho già avuto il livello dati usando la richiesta sincrona. E per adattarsi alla sfida del server dovevamo renderlo asincrono e sarebbe stato complicato rifare il livello dati in sincrono. Questo codice gestisce effettivamente l'autenticazione in modo sincrono asincrono :). Quindi lo strato di dati (modello) è ancora intatto perfettamente, senza alcuna modifica in esso. – LolaRun

+0

Ora riguardo alla sicurezza della gestione delle sfide. Ho letto questo Artile: https://developer.apple.com/library/ios/#technotes/tn2232/_index.html#//apple_ref/doc/uid/DTS40012884-CH1-SECRESOLVINGFAILURES E il mio caso non è dove il mio server ha un certificato verificato, è stato autofirmato e rimarrà in questo modo. E nessuna CA padre per il certificato del server. Quindi, o questo, o scaricare il certificato e confrontare i dati. E penso che entrambi gli approcci abbiano la stessa vulnerabilità di attacco. Quindi dobbiamo lavorare con il server per renderlo più sicuro. – LolaRun