Evgenii Legotckoi
Evgenii Legotckoi04 травня 2017 р. 11:33

Qt/C++ - Урок 065. Відповідність помилок HTTP помилкам відповіді сервера в QNetworkAccessManager

В одному з уроків було представлено роботу з QNetworkAccessManager для отримання вмісту сторінки з сайту за протоколом http. Там була зроблена перевірка на наявність помилок, але були дані пояснення, які можуть бути помилки. Для цього клас QNetworkReply надає enum NetworkError , у якому перераховані коди можливих помилок.

У разі успішного виконання повертається NoError , рівний 0 .

В іншому випадку повертається код помилки з кодів, наведених нижче:


Постійна Значення Опис
QNetworkReply::ConnectionRefusedError
1
Видалений сервер відхилив з'єднання (сервер не приймає запити)
QNetworkReply::RemoteHostClosedError
2
віддалений сервер закрив з'єднання передчасно, до того, як вся відповідь була отримана та оброблена
QNetworkReply::HostNotFoundError
3
віддалений хост не знайдено (недійсне ім'я хоста)
QNetworkReply::TimeoutError
4
підключення до віддаленого сервера закінчилося
QNetworkReply::OperationCanceledError
5
операцію було скасовано через виклик abort() або close() до завершення.
QNetworkReply::SslHandshakeFailedError
6
Підключення через SSL/TLS не вдалося, шифрований канал не може бути. Повинен випромінювати сигнал sslErrors().
QNetworkReply::TemporaryNetworkFailureError
7
з'єднання було порушено через відключення від мережі, проте система ініціювала роумінг до іншої точки доступу. Запит повинен бути повторно та буде оброблений, як тільки з'єднання буде відновлено.
QNetworkReply::NetworkSessionFailedError
8
з'єднання було порушено через відключення від мережі або неможливості запуску мережі.
QNetworkReply::BackgroundRequestNotAllowedError
9
запит на даний час не допускається через політику платформи.
QNetworkReply::TooManyRedirectsError
10
кількість редиректів перевищила допустимий ліміт. За промовчанням ліміт встановлено на 50 редиректів через QNetworkRequest::setMaxRedirectsAllowed().
QNetworkReply::InsecureRedirectError
11
під час обробки редиректів, API доступу по мережі виявило редирект із шифрованого протоколу (https) на не шифрований (http)
QNetworkReply::ProxyConnectionRefusedError
101
у підключенні до проксі-сервера відмовили (проксі-сервер не приймає запити)
QNetworkReply::ProxyConnectionClosedError
102
проксі-сервер закрив з'єднання передчасно, до того, як вся відповідь була отримана та оброблена
QNetworkReply::ProxyNotFoundError
103
проксі-хост не знайдено (недійсне ім'я проксі хоста)
QNetworkReply::ProxyTimeoutError
104
підключення до проксі-сервера закінчилося або проксі-сервер не відповів вчасно на відправлений запит
QNetworkReply::ProxyAuthenticationRequiredError
105
проксі-сервер вимагає аутентифікації для того, щоб задовольнити запит, але не прийняв будь-яких запропонованих облікових даних (якщо є)
QNetworkReply::ContentAccessDenied
201
у доступі до віддаленого контенту відмовлено (за аналогією з помилкою HTTP 401)
QNetworkReply::ContentOperationNotPermittedError
202
Запитана операція на віддалений вміст не допускається
QNetworkReply::ContentNotFoundError
203
віддалений контент не знайдено на сервері (аналогічно помилці HTTP 404)
QNetworkReply::AuthenticationRequiredError
204
віддалений сервер вимагає аутентифікації, щоб надати контент, але надані облікові дані не були прийняті (якщо є)
QNetworkReply::ContentReSendError
205
запит необхідно надіслати повторно, але це не вдалося, наприклад, тому що завантаження даних не може бути прочитане вдруге.
QNetworkReply::ContentConflictError
206
запит не може бути завершено через конфлікт із поточним станом ресурсу.
QNetworkReply::ContentGoneError
207
Запитаний ресурс більше не доступний на сервері.
QNetworkReply::InternalServerError
401
Сервер зіткнувся з непередбаченою умовою, яка дозволяє йому виконати запит.
QNetworkReply::OperationNotImplementedError
402
сервер не підтримує функціональних можливостей, необхідних для виконання запиту.
QNetworkReply::ServiceUnavailableError
403
сервер не може обробити запит на даний момент.
QNetworkReply::ProtocolUnknownError
301
Network Access API неспроможна задовольнити запит, оскільки протокол не відомий
QNetworkReply::ProtocolInvalidOperationError
302
запитана операція неприпустима цього протоколу
QNetworkReply::UnknownNetworkError
99
було виявлено невідому помилку мережі
QNetworkReply::UnknownProxyError
199
було виявлено невідому помилку проксі
QNetworkReply::UnknownContentError
299
було виявлено невідому помилку, пов'язану з віддаленим вмістом
QNetworkReply::ProtocolFailure
399
був виявлений збій у протоколі (помилка синтаксичного аналізу, недійсні чи несподівані відповіді тощо)
QNetworkReply::UnknownServerError
499
було виявлено невідому помилку, пов'язану з відповіддю сервера

Після вивчення даного списку помилок можна зробити висновок, що цей список поєднує значно більший список помилок, ніж, наприклад, той список кодів помилок, який може повернути http сервер. Давайте поговоримо трохи про можливі помилки і через що вони можуть виникнути.

QNetworkReply::ConnectionRefusedError і QNetworkReply::RemoteHostClosedError

Якщо говорити про інтерпретацію даних помилок, то найбільш яскравим прикладом для мене є підключення SSH до іншого хосту. Сенс помилок у цьому, що у першому випадку сервер нас не пускає, тоді як у другому випадку з'єднання може бути закрито після закінчення певного періоду часу.

Також помилка ConnectionRefusedError може виникати у випадках, коли на певному порту ПК просто немає служби, яка б обробила запит.

QNetworkReply::HostNotFoundError

Мабуть, досить зрозуміла помилка, яка означає, що ви просто ввели невірну ip адресу або домен, з якого намагаєтеся отримати дані. Також, така помилка може виникнути в тому випадку, якщо домен перестав бути доступним у мережі. Ця помилка аналогічна до помилки номер 105 - ERR_NAME_NOT_RESOLVED (HTTP).

QNetworkReply::TimeoutError

Перевищено інтервал очікування. Найбільш близьке порівняння - це використання протоколу ICMP, перевірка доступності вузла в мережі, коли робимо його ping. Тобто вузол у мережі начебто і є, але він не відповідає.

QNetworkReply::OperationCanceledError

А ось помилка, яка буде ставитися вже до дій програми на Qt. В даному випадку вона буде виникати тоді, коли логіка програми перериває отримання даних через QNetworkAccessManager. Тобто дана помилка не повинна виникати в тому випадку, якщо операцію отримання даних було перервано ззовні. Тому якщо Ви відловлюєте подібну помилку, то шукайте проблему всередині вашої власної програми.

QNetworkReply::SslHandshakeFailedError

Для встановлення шифрованих каналів зв'язку, які використовують шифрування SSL, потрібне встановлення з'єднання через операції квитування, тобто через підтвердження прийому/передачі інформації. В даному випадку здійснюється узгодження параметрів шифрування, передача сеансового ключа, а також необов'язкові операції автентифікації сервера клієнта та сервера. Якщо щось із перерахованого піде не так, то буде викинуто цю помилку.

QNetworkReply::TemporaryNetworkFailureError і QNetworkReply::NetworkSessionFailedError

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

Клас QNetworkInterface має статичний метод QList QNetworkInterface::allInterfaces() , який повертає список усіх інтерфейсів на вашому комп'ютері. При цьому будуть враховуватися абсолютно всі з'єднання, аж до з'єднань, які були створені для віртуальної машини, наприклад, для Virtual Box. Тут до речі виникає дуже цікавий момент, коли ведеться розробка програмного забезпечення, яке має працювати по мережі, і при цьому розробник має віртуальну машину на борту, особливо якщо вона запущена, то необхідно враховувати цей момент, оскільки програма може намагатися отримати дані через з'єднання з віртуальною машиною, тобто вважатиме що мережа доступна, хоча розробник тестуватиме User Case при відключеному з'єднанні . Втім, навіть вимкнена віртуальна машина викликатиме деякі проблеми, оскільки з'єднання буде активно, хоча Link і не буде піднято.

Тому, щоб зрозуміти, що не так, при отриманні помилок QNetworkReply::TemporaryNetworkFailureErro r та QNetworkReply::NetworkSessionFailedError доведеться протестувати інтерфейси ПК на предмет активності: QNetworkInterface::IsUp та ::IsRunning.

QNetworkReply::BackgroundRequestNotAllowedError

А ось ця помилка залежить безпосередньо від політик платформи, для якої розробляється програма. Наприклад, якщо під деяким абстрактним Android пристроєм заборонено обмін інформацією по мережі в енергозберігаючому режимі, то в даному режимі ми отримуватимемо саме цю помилку, при спробі обміну інформацією.

QNetworkReply::TooManyRedirectsError і QNetworkReply::InsecureRedirectError

А ось ці помилки з розряду нового в Qt 5.6. Тепер можна відслідковувати перевищення кількості редиректів зі сторінок сайтів, а також редиректи зі сторінок із шифруванням https на сторінки без шифрування. Що може бути корисним для розробки програмного забезпечення для аналізу сайтів.

Без додаткових налаштувань дані помилки зазвичай не виникають. Справа в тому, що коли задається QNetworkRequest і в нього не встановлюються прапори конфігурації, то при спробі запиту сторінки із сайту, з якої здійснюється редирект, не відбуватиметься переходу на новий url, а в QNetworkReply не буде жодного корисного контенту. Тому потрібно встановити в QNetworkRequest прапорець QNetworkRequest::FollowRedirectsAttribute, тоді QNetworkAccessManager буде переходити по редиректах, поки не отримає підсумкову сторінку або не перевищить обмеження на кількість переходів. За замовчуванням кількість переходів обмежена 50-ма.

Встановлення атрибуту може здійснюватися так:

QNetworkRequest request;  
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, QVariant(true));

Що стосується QNetworkReply::InsecureRedirectError, то сенс полягає в тому, щоб відстежити редирект на небезпечний протокол.

Помилки QNetworkReply::Proxy*

Наступні п'ять помилок аналогічні за характером помилок підключення до серверів без проксування.

QNetworkReply::ContentAccessDenied

У документації сказано, що дана помилка аналогічна помилці 401 HTTP, тобто потрібна авторизація, але вважаю, що дана помилка може виникати і у випадках отримання коду 403 і 407. Помилка 407 аналогічна помилці 401, але використовується для проксі-сервера. А помилка 403 є породжувальною для помилок 401 та 407.

QNetworkReply::AuthenticationRequiredError

Ця помилка характерна для протоколу HTTP. Справа в тому, що http протокол підтримує схеми автентичності. В даному випадку необхідно надсилати запит на сервер із встановленням логіну та пароля. Зауважу, що це безпосередньо означає те, що Ви можете написати додаток на Qt, який автентифікуватиметься на сайтах і виконувати певні дії на сайті вже в авторизованому режимі, тобто можна написати і бота для роботи на сайті.

Вирішення проблеми полягає в тому, щоб встановити логін та пароль користувача в QAuthenticator, який буде підмішувати облікові дані до запиту. Причому робитися це буде в автоматичному режимі за сигналом QNetworkAccessManager::authenticationRequired, при цьому логін та пароль будуть кешовані, тому сигнал не буде випускатися при кожному запиті.

connect(&m_manager,&QNetworkAccessManager::authenticationRequired,
        [this](QNetworkReply *rep, QAuthenticator* auth){
            auth->setUser("username");
            auth->setPassword("passwordd");
        });

QNetworkReply::ContentReSendError

Провести будь-яку точну аналогію з кодами HTTP для цієї помилки є складним, оскільки викликатись вона може різними причинами.

QNetworkReply::ContentConflictError

Ця помилка відповідає помилці 409 Confilct у протоколі HTTP.

QNetworkReply::ContentGoneError

Ця помилка відповідає помилці 410 Gone (Видалений) у протоколі HTTP.

QNetworkReply::InternalServerError

Ця помилка відповідає помилці 500 Internal Server Error (Внутрішня помилка сервера) у протоколі http.

QNetworkReply::OperationNotImplementedError

Ця помилка відповідає помилці 501 Not Implemented (Не реалізовано) у протоколі http. Виникає така тоді, коли Ви намагаєтеся виконати, наприклад, запит POST до URL, яким сервер обробляє лише GET запити.

Таку поведінку можна зустріти, наприклад, у проекті Django . Якщо запит не реалізований, сервер з Django відправить порожню сторінку на POST запит з цим кодом.

QNetworkReply::ProtocolUnknownError

Така помилка, як QNetworkReply::ProtocolUnknownError, може виникнути через те, що запит було передано url без вказівки типу протоколу, тобто замість

http://www.example.com

було передано

//www.example.com

Така проблема може виникнути в тому випадку, якщо ви парсіте сторінки і виймаєте url зображень. Наприклад, на даному сайті адреси всіх зображень у статтях виглядають таким чином

/media/uploads/2017/02/03/testquickwidget.jpg

Тобто не вказується протокол та домен сайту. Тому якщо Ви витягнете всі адреси зображень зі сторінки, то не зможете завантажити зображення без додаткової обробки, а саме без встановлення домену і протоколу на початку рядка, отримавши цю помилку.

QNetworkReply::ServiceUnavailableError

Відповідає помилці 503 Service Unavailable («сервіс недоступний») у протоколі http

QNetworkReply::ProtocolInvalidOperationError

У цьому випадку протокол визначено, але точна відповідність помилці з протоколу http не простежується, щодо інших протоколів також може бути будь-що.

QNetworkReply::UnknownNetworkError

Найчастіший варіант того, чому може відповідати дана помилка є помилка шлюзу 502 Bad Gateway («поганий, помилковий шлюз») у протоколі http

QNetworkReply::UnknownProxyError

Також може бути помилка 502, але вже у варіанті з проксі-сервером

Ошибки QNetworkReply::UnknownContentError,QNetworkReply::ProtocolFailure, QNetworkReply::UnknownServerError

З цими помилками важко знайти робочу відповідність, буду радий підказці, якщо хтось стикався.

Приклад з виведенням помилки в qDebug

Ви можете перевірити помилку сигналу завершення запиту від QNetworkAccessManager у слоті, який підключається для обробки результату запиту.

manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this, &Downloader::onResult);

У цьому випадку є клас-обгортка над класом QNetworkAccessManager під назвою Downloader . Цей клас має слот onResult , який у свою чергу відповідає за обробку результату відповіді QNetworkAccessManager .

void Downloader::onResult(QNetworkReply *reply)
{
    // Если в процессе получения данных произошла ошибка
    if(reply->error()){
        // Сообщаем об этом и показываем информацию об ошибках
        qDebug() << "ERROR";
        // Здесь получаем один из enum NetworkError, то есть код ошибки
        qDebug() << reply->error();
    } else {
        // ToDo something
    }
}
Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

KL
  • 05 травня 2017 р. 09:52

Unable to init SSL Context: Выдает приложение, что это может быть?

Evgenii Legotckoi
  • 05 травня 2017 р. 11:19

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

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
d
  • dsfs
  • 26 квітня 2024 р. 04:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
d
  • dsfs
  • 26 квітня 2024 р. 04:45

C++ - Тест 002. Константы

  • Результат:50бали,
  • Рейтинг балів-4
d
  • dsfs
  • 26 квітня 2024 р. 04:35

C++ - Тест 001. Первая программа и типы данных

  • Результат:73бали,
  • Рейтинг балів1
Останні коментарі
k
kmssr08 лютого 2024 р. 18:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 01:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 10:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 08:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik18 грудня 2023 р. 21:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi02 травня 2024 р. 14:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderChe
IscanderChe30 квітня 2024 р. 04:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
G
Gar22 квітня 2024 р. 05:46
Clipboard Как скопировать окно целиком в clipb?
Павел Дорофеев
Павел Дорофеев14 квітня 2024 р. 02:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex04 квітня 2024 р. 04:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Слідкуйте за нами в соціальних мережах