2012-02-15 15 views
9

En mi aplicación iOS, estoy usando un UIWebView y un protocolo personalizado (con mi propia implementación de NSURLProtocol). He estado bastante cuidado en asegurarse de que cada vez que se carga una URL, me carga algo como esto en mi UIWebView:Uso de un NSURLProtocol personalizado con UIWebView y solicitudes POST

myprotocol: // myserver/miruta

y en mi aplicación NSURLProtocol, tomo un mutable copia de NSURLRequest, convierta la URL a http: y envíela a mi servidor.

Todo funciona para las solicitudes HTTP GET. El problema que encuentro es con las solicitudes POST. Parece que UIWebView no codifica correctamente los datos del formulario en el HTTPBody si la solicitud utiliza mi protocolo personalizado.

Una solución, ya que estoy usando HTTPS para mis solicitudes de servidor, es que registro mi controlador de protocolo para interceptar http: en lugar de myprotocol: y puedo convertir todas las llamadas a https: esta otra pregunta, here, Me señaló a esa solución:

Pero me pregunto si hay alguna manera alternativa y/o mejor de lograr lo que quiero.

Respuesta

5

En lugar de tratar de utilizar las peticiones POST, una solución es seguir utilizando peticiones GET para myprotocol:// URL, pero transformarlas en su aplicación NSURLProtocol a una solicitud de http://y POST al servidor utilizando la cadena de solicitud de consulta como el cuerpo del POST.

La preocupación de usar solicitudes GET para enviar grandes cantidades de datos es que en algún punto a lo largo de la cadena de solicitud, la línea de solicitud puede quedar truncada. Sin embargo, esto parece no ser un problema con los protocolos implementados localmente.

escribí una aplicación de prueba corta Córdoba para experimentar y me pareció que yo era capaz de enviar a través de un poco más de 1 MiB de datos sin problemas a la solicitud HTTP haciéndose eco de servicio http://http-echo.jgate.de/

Aquí está mi startLoading aplicación:

- (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]; 
    } 
} 

entonces implementarse los NSURLConnection métodos de protocolo que transmita al el método apropiado NSURLProtocolClient, pero la construcción de seguridad de los datos de respuesta en el caso de Transfer-Encoding:chunked (como es el caso para las respuestas de http://http-echo.jgate.de/).

+0

Sugerencia agradable. Lo siento, no he notado su respuesta antes. – bcholmes

2

Desafortunadamente, parece que las solicitudes de esquema http: y https: se manejan de forma ligeramente diferente que otros esquemas (incluido los personalizados) de Foundation Framework. Obviamente HTTPBody y HTTPBodyStream llama en NSURLRequest devuelve siempre nil para los anteriores. Esto ya se decidió antes de la llamada de [NSURLProtocol canInitWithRequest] por lo tanto, la implementación personalizada NSURLProtocol no tiene forma de influir en eso (es demasiado tarde).

Parece que se utiliza una clase NSURLRequest diferente para http: y https: que 'una predeterminada'. La implementación predeterminada de GnuStep de esta clase devuelve siemprenil de HTTPBody y HTTPBodyStream llamadas. Por lo tanto, las implementaciones particulares (por ejemplo, una en PhoneGap, probablemente parte de Foundation Framework) eligen NSURLRequest -tipo de clase basado en el esquema previa consultando con NSURLProtocol.Para los esquemas personalizados, obtiene NSURLRequest que devuelve nil para HTTPBody y HTTPBodyStream, lo que efectivamente desactiva el uso del método POST (y otros métodos con el cuerpo) en el manejador de esquema de URI personalizado.

Tal vez hay una manera de cómo influir en la decisión de qué clase de NSURLRequest se usa realmente, pero actualmente no lo sé.

Como solución alternativa, puede seguir utilizando el esquema http: o https: y decidir en [NSURLProtocol canInitWithRequest] en función de otros criterios (por ejemplo, nombre de host).

Cuestiones relacionadas