Mulipartpost NSURLПроблемы с подключением по сети 3G

у нас есть приложение для iOS, которое загружает изображения на сервер, используя составной пост. При использовании Wi-Fi все в порядке, но в 3G для больших изображений мы получаем ошибки сети.

На клиенте (iPhone):

Я получил

Домен = код NSURLErrorDomain = -1021 «поток тела запроса исчерпан»

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

На сервере:

Я настроил прокси для просмотра запроса, и я получаю

"Раструб сломанной трубы"

обычно после передачи 740Кб

Итак, что я делаю неправильно? Как я уже сказал, через Wi-Fi все работает нормально, и в 3G с небольшими изображениями тоже все в порядке.

Код версии AFNetwork (останавливает передачу после 600 - 800 кб для больших изображений):

AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:self.baseURL];

        request = [client multipartFormRequestWithMethod:@"POST"
                                                                         path:nil
                                                                   parameters:nil
                                                    constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
                                        {

                                            for (NSString* partType in self.parts) {
                                                if ([partType isEqualToString:@"jsonpart"]) {
                                                    [formData appendPartWithFormData:[self.parts objectForKey:partType] name:@"@json"];
                                                }
                                                else{ //is an image for sure
                                                    [formData appendPartWithFileData:[self.parts objectForKey:partType]
                                                                                name:partType
                                                                            fileName:[NSString stringWithFormat:@"%@-%d.jpg", partType, [partType hash]]
                                                                            mimeType:@"image/jpeg"];
                                                }

                                            }

                                            [formData throttleBandwidthWithPacketSize:kAFUploadStream3GSuggestedPacketSize delay:kAFUploadStream3GSuggestedDelay];
                                        }];

        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

        [client enqueueHTTPRequestOperation:operation];

person PakitoV    schedule 07.06.2013    source источник
comment
Какой у вас оператор мобильной связи? Кроме того, вы пытались использовать throttleBandwidthWithPacketSize:delay: с более низкими значениями, чем рекомендуемые значения по умолчанию?   -  person Guillaume Algis    schedule 07.06.2013
comment
Да, я пробовал это. Та же проблема бывает с разными операторами связи.   -  person PakitoV    schedule 07.06.2013


Ответы (2)


Уточнение, что означает ошибка и откуда она может появиться:

Вы получаете эту ошибку, когда запрос настроен с HTTPBodyStream и явно установленным заголовком Content-Length, а входной поток не предоставляет столько байтов, сколько указано в заголовке Content-Length. То есть нижележащее соединение получило EOF из входного потока до того, как указанное количество байтов могло быть прочитано из потока.

Таким образом, причиной может быть неправильно рассчитанная длина содержимого составного тела. Это вполне вероятно, так как вычисление длины multipart довольно подвержено ошибкам.

Ошибка также возникает, если вы получили redirect-ответ, а входной поток уже был открыт и, возможно, были прочитаны какие-то данные. Ответ перенаправления требует, чтобы входной поток был «перемотан назад», чтобы его можно было прочитать с самого начала, когда будет получен правильный ответ. Это происходит не автоматически и должно быть явно реализовано в делегате. (Посмотрите на AFNetworking, "перематывает" ли он как-то входной поток в случае редиректа - то есть реализован ли connection:needNewBodyStream:).

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

Также может случиться так, что эта ошибка является побочным эффектом другой ошибки, и что эта ошибка маскирует исходную ошибку.

Также может случиться так, что внутренний подкласс NSInputStream, который используется для выполнения запроса составной формы в AFNetworking, имеет ошибку. ИМХО, реализация немного сомнительна, и в других местах определенно есть потенциальная ошибка, связанная с потоками.

person CouchDeveloper    schedule 07.06.2013
comment
Но если бы это было так, как это возможно, что работает через Wi-Fi, но не через 3G с точно таким же кодом? - person PakitoV; 08.06.2013
comment
Отличный вопрос! Возможно, ответ можно найти в трассировке пакетов, которая перехватывает пакеты как человек посередине. Но сначала я бы проверил, был ли вызван метод делегата connection:needNewBodyStream: (возможно, в результате проверки подлинности) и будет ли сетевая библиотека сбрасывать HTTPBodyStream запроса. - person CouchDeveloper; 09.06.2013
comment
Вы также можете проверить, будет ли запрос работать, если вы настроите запрос с NSData (через свойство HTTPBody) вместо потока. Поскольку NSData может быть перемотан внутри соединения, нет проблем, когда запрос аутентификации вызвал повторную отправку запроса. Обратите внимание, что все это может происходить прозрачно, поэтому вам следует проверить с помощью отладчика и трассировки пакетов. - person CouchDeveloper; 09.06.2013
comment
В моем случае использование Simulator if дает сбой каждый раз, если я не отправляю два запроса на загрузку одновременно. Затем оба преуспевают, и любая последующая одиночная загрузка также завершается успешно, пока я в следующий раз не запущу Симулятор. Есть идеи? - person Rivera; 24.09.2014

Хорошо, после многих часов, потраченных на это, я наконец получил это. Ничего общего с кодом, по какой-то причине здесь играет роль корпоративный брандмауэр. С выключенным брандмауэром все работает нормально. Странно, но это решает проблему и выходит за рамки iOS или кода.

person PakitoV    schedule 07.06.2013
comment
Как вы отключили брандмауэр на устройстве? - person CouchDeveloper; 07.06.2013
comment
Нет, я имел в виду брандмауэр, защищающий сервер компании, на который я отправлял данные. После этого каждый тест, который раньше не работал, просто работал. - person PakitoV; 08.06.2013
comment
OK. Что это за сервер? Если это приложение Rails, другие сообщают, что здесь помогло отключение protect_from_forgery ‹ruby.about .com/od/mr/g/protectforgery.htm›. Этот флаг безопасности, который предотвращает атаки CSFR, не требуется для контроллеров чистого API, а только для контроллеров, обслуживающих HTML-страницы. Другие приложения веб-сервера могут иметь аналогичный механизм. Пожалуйста, включите брандмауэр снова! ;) - person CouchDeveloper; 09.06.2013