NSURLRequest: как обрабатывать перенаправленный пост?

У меня есть проверенное и проверенное использование реализации NSURLRequest (и сопровождений), которая отлично подходит для GET и POST для заданного URL.

Тем не менее, я хочу переместить цель URL-адреса без изменения URL-адреса, используемого приложением, поэтому я намереваюсь использовать перенаправление веб-хостинга через своего DNS-провайдера.

Это отлично подходит для запросов GET, но POST просто зависает... никакой ответ на соединение не получен.

Соответствующий метод iOS для обработки перенаправления -

-(NSURLRequest *)connection:(NSURLConnection *)connection
    willSendRequest:(NSURLRequest *)request
    redirectResponse:(NSURLResponse *)redirectResponse

Согласно документации Apple (обработка переадресаций),

Если делегат не реализует соединение: willSendRequest: redirectResponse: все канонические изменения и перенаправления серверов разрешены.

Ну, это не мой опыт, потому что оставлять этот метод не работает для меня. Запрос просто зависает без ответа.

Apple также предлагает реализацию, willSendRequest (см. выше связанную документацию Apple), опять же это не работает для меня. Я вижу вызовы, но полученные запросы просто зависают.

Моя текущая реализация willSendRequest выглядит следующим образом (см. ниже). Это следует за перенаправлением, но обрабатывает запрос так, как если бы он был GET, а не POST.

Я считаю, что проблема заключается в том, что перенаправление теряет тот факт, что HTTP-запрос является POST (может быть больше проблем, например, перенос запроса Body forward тоже?).

Я не уверен, что я должен делать здесь. Таким образом, любой совет о том, как правильно обрабатывать POST, который получает перенаправление, будет оценен по достоинству. Спасибо.

-(NSURLRequest *)connection:(NSURLConnection *)connection
   willSendRequest:(NSURLRequest *)request
  redirectResponse:(NSURLResponse *)redirectResponse
{

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) redirectResponse;

    int statusCode = [httpResponse statusCode];


    NSLog (@"HTTP status %d", statusCode);

    // http statuscodes between 300 & 400 is a redirect ...
    if (httpResponse && statusCode >= 300 && statusCode < 400)
    {
        NSLog(@"willSendRequest (from %@ to %@)", redirectResponse.URL, request.URL);
    }

    if (redirectResponse)
    {
        NSMutableURLRequest *newRequest = [request mutableCopy]; // original request

       [newRequest setURL: [request URL]];

       NSLog (@"redirected");

       return newRequest;
    }
    else
    {
        NSLog (@"original");

       return request;
    }
}

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ 1

Код HTTP, полученный методом willSendRequest, равен 301 - "Перенос постоянно".

Используя allHTTPHeaderFields для извлечения полей заголовка, я вижу, что он запрашивает, что я изначально представляю, имеет заголовок

HTTP header {
  "Content-Length" = 244;
  "Content-Type" = "application/json";
}

... и у скопированного/перенаправленного запроса есть заголовок,

Redirect HTTP header {
  Accept = "*/*";
  "Accept-Encoding" = "gzip, deflate";
  "Accept-Language" = "en-us";
  "Content-Type" = "application/json";
}

... который не похож на копию исходного запроса или даже надмножество.

Ответ 1

Сохраняйте свой первоначальный запрос, затем предоставьте свой собственный willSendRequest:redirectResponse:, чтобы настроить этот запрос, а не работать с тем, который Apple предоставляет вам.

- (NSURLRequest *)connection: (NSURLConnection *)connection
             willSendRequest: (NSURLRequest *)request
            redirectResponse: (NSURLResponse *)redirectResponse;
{
    if (redirectResponse) {
        // The request you initialized the connection with should be kept as
        // _originalRequest.
        // Instead of trying to merge the pieces of _originalRequest into Cocoa
        // touch proposed redirect request, we make a mutable copy of the
        // original request, change the URL to match that of the proposed
        // request, and return it as the request to use.
        //
        NSMutableURLRequest *r = [_originalRequest mutableCopy];
        [r setURL: [request URL]];
        return r;
    } else {
        return request;
    }
}

Выполняя это, вы явно игнорируете некоторые аспекты спецификации HTTP: перенаправления обычно должны быть преобразованы в запросы GET (в зависимости от кода состояния HTTP). Но на практике это поведение будет лучше вам работать при отправке POST из приложения iOS.

См. также:

Ответ 2

Спецификация HTTP для обработки кодов статуса 3xx очень не приветствуется в отношении протоколов, отличных от GET и HEAD. Он ожидает какого-то взаимодействия с пользователем на промежуточном этапе перенаправления, что привело к множеству несовместимых клиентских и серверных реализаций, а также к серьезной головной боли для разработчиков веб-сервисов.

С точки зрения iOS NSURL одна из вещей, которую вы можете проверить, - это то, что исходное тело POST включено в новый запрос на перенаправление.

Исходя из ваших комментариев по моему первоначальному ответу и редактирования вашего вопроса, похоже, что URL-адрес, к которому вы пытаетесь получить доступ, постоянно обновляется (код статуса 301). В этом случае вы можете вообще избежать перенаправления, используя новый URL.