Использование собственного NSURLProtocol с запросами UIWebView и POST - PullRequest
10 голосов
/ 16 февраля 2012

В моем приложении для iOS я использую UIWebView и собственный протокол (с моей собственной реализацией NSURLProtocol).Я был довольно осторожен с тем, чтобы всякий раз, когда я загружал URL, я загружал что-то подобное в мой UIWebView:

myprotocol: // myserver / mypath

и в моей реализации NSURLProtocol,Я беру изменчивую копию NSURLRequest, преобразовываю URL в http: и отправляю это на мой сервер.

Все работает для запросов HTTP GET.Проблема, с которой я сталкиваюсь, связана с запросами POST.Похоже, что UIWebView неправильно кодирует данные формы в HTTPBody, если в запросе используется мой настраиваемый протокол.

Один способ, поскольку я использую HTTPS для запросов к серверу, - это регистрациямой обработчик протокола для перехвата http: вместо myprotocol: и я могу преобразовать все вызовы в https: этот другой вопрос здесь указал мне на это решение:

Но мне интересно,есть какой-то альтернативный и / или лучший способ выполнить то, что я хочу.

Ответы [ 2 ]

6 голосов
/ 30 июня 2012

Вместо того, чтобы пытаться использовать POST-запросы, один из обходных путей состоит в том, чтобы продолжить использовать GET-запросы для myprotocol:// URL-адресов, но преобразовать их в вашей NSURLProtocol реализации в http:// и POST-запрос для ваш сервер использует строку запроса в качестве тела сообщения POST.

Проблема с использованием запросов GET для отправки больших объемов данных заключается в том, что где-то в цепочке запросов строка запроса может быть обрезана. Однако, это не проблема для локально реализованных протоколов.

Я написал короткое тестовое приложение Cordova для эксперимента и обнаружил, что могу без проблем отправлять чуть более 1 МБ данных в службу эхо-запросов HTTP http://http -echo.jgate.de /

Вот моя 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];
    }
}

Затем я применил методы протокола NSURLConnection для пересылки к соответствующему методу NSURLProtocolClient, но на основе данных ответа в случае Transfer-Encoding:chunked (как в случае ответов от http://http - echo.jgate.de/).

4 голосов
/ 01 января 2014

К сожалению, похоже, что запросы схем http: и https: обрабатываются в Foundation Framework несколько иначе, чем другие (включая пользовательские) схемы.Очевидно, что HTTPBody и HTTPBodyStream вызовы соответствующих NSURLRequest всегда возвращают nil для прежних.Это решено уже перед вызовом [NSURLProtocol canInitWithRequest], поэтому пользовательская реализация NSURLProtocol никак не может повлиять на это (слишком поздно).

Кажется, что для http: используется другой класс NSURLRequesthttps: чем «по умолчанию».По умолчанию реализация этого класса GnuStep возвращает всегда nil из вызовов HTTPBody и HTTPBodyStream.Поэтому конкретные реализации (например, одна под PhoneGap, скорее всего, часть Foundation Framework) выбирают тип NSURLRequest класса, основываясь на схеме, предварительно согласовав эту с NSURLProtocol.Для пользовательских схем вы получаете NSURLRequest, который возвращает nil как для HTTPBody, так и HTTPBodyStream, что эффективно отключает использование метода POST (и других методов с телом) в обработчике пользовательских схем URI.

Может бытьесть способ повлиять на решение о том, какой класс NSURLRequest фактически используется, но в настоящее время он мне неизвестен.

В качестве обходного пути вы все еще можете использовать схему http: или https: и принять решение в[NSURLProtocol canInitWithRequest] на основе других критериев (например, имя хоста).

...