2012-02-15 11 views
9

Nella mia app iOS, sto utilizzando un UIWebView e un protocollo personalizzato (con la mia implementazione NSURLProtocol). Sono stato abbastanza attento a fare in modo che ogni volta che carico un URL, mi carico qualcosa di simile nella mia UIWebView:Utilizzo di un NSURLProtocol personalizzato con UIWebView e le richieste POST

myprotocol: // myserver/mypath

e nella mia implementazione NSURLProtocol, prendo un mutabile copia di NSURLRequest, converti l'URL in http: e invialo al mio server.

Tutto funziona per richieste HTTP GET. Il problema che incontro è con le richieste POST. Sembra che UIWebView non codifichi correttamente i dati del modulo in HTTPBody se la richiesta utilizza il mio protocollo personalizzato.

Una soluzione, poiché sto utilizzando HTTPS per le richieste del mio server, è che registro il gestore del protocollo per intercettare http: anziché myprotocol: e posso convertire tutte le chiamate in https: Questa altra domanda, here, mi ha indirizzato verso quella soluzione:

Ma mi chiedo se ci sia un modo alternativo e/o migliore per realizzare ciò che voglio.

risposta

5

Invece di cercare di utilizzare richieste POST, un lavoro intorno è quello di continuare a utilizzare le richieste GET per myprotocol:// URL, ma trasformarli in NSURLProtocol implementazione a una richiesta http://e POST al server utilizzando la stringa di richiesta query come corpo del POST.

La preoccupazione con l'utilizzo di richieste GET per inviare grandi quantità di dati è che da qualche parte lungo la catena di richieste, la linea di richiesta potrebbe essere troncata. Questo sembra non essere un problema, tuttavia, con i protocolli implementati localmente.

ho scritto un breve Cordova Test App per sperimentare e ho scoperto che ero in grado di inviare attraverso un po 'più di 1 Mb di dati senza difficoltà alla richiesta HTTP eco servizio http://http-echo.jgate.de/

Ecco la mia startLoading implementazione:

- (void)startLoading { 
    NSURL *url = [[self request] URL]; 
    NSString *query = [url query]; 
    // Create a copy of `url` without the query string. 
    url = [[[NSURL alloc] initWithScheme:@"http" host:@"http-echo.jgate.de" path:[url path]] autorelease]; 
    NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:url]; 
    [newRequest setHTTPMethod:@"POST"]; 
    [newRequest setAllHTTPHeaderFields:[[self request] allHTTPHeaderFields]]; 
    [newRequest addValue:@"close" forHTTPHeaderField:@"Connection"]; 
    [newRequest addValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; 
    [newRequest setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]]; 
    urlConnection = [[NSURLConnection alloc] initWithRequest:newRequest delegate:self]; 
    if (urlConnection) { 
     receivedData = [[NSMutableData data] retain]; 
    } 
} 

ho quindi attuato le NSURLConnection metodi del protocollo di trasmettere al metodo appropriato NSURLProtocolClient, ma accumulando i dati di risposta nel caso di Transfer-Encoding:chunked (come è il caso per le risposte da http://http-echo.jgate.de/).

+0

Bel suggerimento. Scusa, non ho notato la tua risposta, prima. – bcholmes

2

Sfortunatamente sembra che le richieste di schema http: e https: siano gestite in modo leggermente diverso rispetto ad altri schemi (compresi quelli personalizzati) di Framework Foundation. Ovviamente le chiamate HTTPBody e HTTPBodyStream relative al numero NSURLRequest restituiscono sempre nil per quelle precedenti. Questo è deciso già prima chiamata di [NSURLProtocol canInitWithRequest] pertanto l'implementazione personalizzata NSURLProtocol non ha modo di influenzarla (è troppo tardi).

Sembra che una diversa classe NSURLRequest sia utilizzata per http: e https: di "predefinita". L'implementazione predefinita di GnuStep di questa classe restituisce semprenil da HTTPBody e HTTPBodyStream chiamate. Pertanto particolari implementazioni (ad esempio una sotto PhoneGap, probabilmente parte di Foundation Framework) scelgono il tipo di classe NSURLRequest in base allo schema consultando preventivamente quello con NSURLProtocol.Per gli schemi personalizzati, si ottiene NSURLRequest che restituisce nil per HTTPBody e HTTPBodyStream che disabilita in modo efficace l'utilizzo del metodo POST (e di altri metodi con il corpo) nel gestore di schemi URI personalizzato.

Forse c'è un modo per influenzare la decisione di quale classe è effettivamente utilizzata, ma attualmente è sconosciuta per me.

Per risolvere il problema, è comunque possibile utilizzare http: o https: schema e decidere in [NSURLProtocol canInitWithRequest] sulla base di altri criteri (ad esempio nome host).

Problemi correlati