Utilizzando un NSURLProtocol personalizzato con le richieste UIWebView e POST
-
25-10-2019 - |
Domanda
Nel mio iOS, sto usando un UIWebView e un protocollo personalizzato (con la mia propria 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:
myprotocol: // myserver / mypath
e nella mia implementazione NSURLProtocol, prendo una copia mutabile della NSURLRequest, convertire l'URL http:. E inviare che al mio server
Tutto funziona per le richieste HTTP GET. L'incontro problema che ho è con richieste POST. Sembra che l'UIWebView non codificare correttamente i dati del modulo nel HTTPBody se la richiesta usa il mio protocollo personalizzato.
Un work-around, dal momento che sto utilizzando il protocollo HTTPS per le mie richieste al server, è che registro il mio gestore di protocollo di intercettare http: invece di myprotocol: e posso convertire tutte le chiamate a https: Questa altra domanda, qui , mi ha puntato verso quella soluzione:
Ma mi chiedo se c'è un modo alternativo e / o migliore di realizzare ciò che voglio.
Soluzione
Invece di cercare di utilizzare richieste POST, un lavoro intorno è quello di continuare a utilizzare le richieste GET di URL myprotocol://
, ma trasformarli nell'implementazione NSURLProtocol
a un http://
e richiesta POST al server utilizzando la richiesta stringa di query come il corpo del post.
La preoccupazione con l'utilizzo di richieste GET per inviare grandi quantità di dati è che da qualche parte lungo la catena richiesta, la linea di richiesta potrebbe avere troncato. Questo sembra non essere un problema, però, con i protocolli a livello locale implementati.
ho scritto un breve test app Cordova a sperimentare e ho scoperto che ero in grado di inviare tramite un poco più di 1 Mb di dati senza difficoltà alla richiesta HTTP servizio di eco http://http-echo.jgate.de/
Ecco la mia implementazione startLoading
:
- (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 poi implementato i metodi del protocollo NSURLConnection
di trasmettere al metodo NSURLProtocolClient
appropriato, ma costruire i dati di risposta nel caso di Transfer-Encoding:chunked
(come è il caso per una risposta da http://http-echo.jgate.de/ ).
Altri suggerimenti
Purtroppo sembra che le richieste di schema http:
e https:
vengono gestiti in modo leggermente diverso rispetto agli altri (compresi personalizzato) schemi di Fondazione Framework. Ovviamente le chiamate HTTPBody
e HTTPBodyStream
sui rendimenti NSURLRequest
rilevanti sempre nil
per i più vecchi. Questo è deciso già prima della chiamata del [NSURLProtocol canInitWithRequest]
quindi NSURLProtocol
personalizzato implementazione non ha alcun modo di influenzare che (è troppo tardi).
Sembra che diverse classi NSURLRequest
viene utilizzato per http:
e https:
di 'uno di default'. Predefinito implementazione GNUstep di questa classe restituisce sempre nil
dalle chiamate HTTPBody
e HTTPBodyStream
. Pertanto implementazioni particolari (ad esempio, uno sotto PhoneGap, probabilmente parte di Fondazione quadro) scelgono NSURLRequest
-tipo di classe basata su schema di prima consulenza che con NSURLProtocol
. Per i regimi personalizzati, si ottiene NSURLRequest
che i rendimenti nil
sia per HTTPBody
e HTTPBodyStream
che di fatto disabilita l'uso del metodo POST (e altri metodi con il corpo) in costume gestore schema URI.
Forse c'è un modo per influenzare la decisione di quale classe NSURLRequest
viene effettivamente utilizzato, ma è attualmente sconosciuto per me.
Per risolvere il problema, è comunque possibile utilizzare schema http:
o https:
e decidere in [NSURLProtocol canInitWithRequest]
sulla base di altri criteri (ad esempio nome host).