
Помощник Connexus (Часть 5): HTTP-методы и коды состояния
Введение
Данная статья является продолжением серии статей, в которых мы будем создавать библиотеку под названием Connexus. В первой статье мы разобрались с основами работы функции WebRequest, разобрались с каждым из ее параметров, а также создали пример кода, который демонстрирует использование данной функции и связанные с этим трудности. В прошлой статье мы разобрались с тем, как работает запрос, что такое тело запроса и как отправлять данные на сервер, а в конце разработали поддержку запросов с телом.
В этой пятой статье из серии, посвященной созданию библиотеки Connexus, мы рассмотрим важный аспект протокола HTTP: методы и коды состояния. Понимание того, как работает каждая HTTP-операция и как обрабатывать коды состояния, имеет решающее значение для создания надежного взаимодействия между клиентами и серверами. Поехали!
Методы HTTP
HTTP-методы - это действия, которые мы запрашиваем у сервера для выполнения. При отправке HTTP-запроса, например, для доступа к странице или отправки данных, вы "общаетесь" с сервером, используя эти команды. Вот основные из них:
- GET: Это старое доброе “дай мне это”. Браузер запрашивает доступ к чему-либо на сервере, будь то страница, изображение или файл. Он просто получает информацию, ничего не меняя. Это все равно что попросить меню в ресторане, просто чтобы посмотреть, что там предлагают.
- POST: POST - это парень, доставляющий посылку. Здесь вы отправляете данные на сервер. Это часто встречается в формах, например, при регистрации на веб-сайте. Думайте об этом так, как если бы вы отправляли письмо: вы ждете, пока оно прибудет по назначению, и там что-то сделает, например, зарегистрирует вас.
- PUT: При использовании команды PUT, вы, по сути, говорите: “измените вот это здесь на эту новую версию”. Используется для обновления существующего ресурса. Это как замена масла в вашем автомобиле – это та же самая машина, но теперь с чем-то новым.
- DELETE: Довольно очевидно, да? Это значит “убери это оттуда”. Вы просите сервер что-то удалить. Прощай, больше мы с тобой никогда не увидимся.
- PATCH: PATCH работает деликатнее. Изменяет только часть ресурса. Это все равно что чинить сломанную деталь игрушки – вам не нужно все менять, просто исправьте то, что сломано.
- HEAD: Это та же команда GET, но без тела. Вам нужна только информация о заголовке, а не о содержимом. Это все равно что читать название книги, не открывая страниц.
Существуют и другие методы, такие как CONNECT, OPTIONS и TRACE, но они редко используются в повседневной работе разработчиков. Я не буду здесь подробно описывать каждый из них, но моя цель в работе с библиотекой заключается в том, чтобы она могла поддерживать все HTTP-методы. Если вы хотите больше узнать обо всех методах HTTP, ознакомьтесь с полной документацией по протоколу здесь. Но поверьте мне, самых распространенных запросов в повседневной работе разработчиков, таких как GET, POST и DELETE, достаточно для решения большинства проблем.
Хочу подчеркнуть, что мы используем только один метод для каждого запроса, то есть запрос не может быть типов GET и POST одновременно.
Создание класса CHttpMethod
Теперь, когда мы разобрались с каждым HTTP-методом, для чего он нужен и когда его использовать, давайте перейдем непосредственно к коду. Мы реализуем в Connexus класс, отвечающий за хранение HTTP-метода, который будет использоваться для выполнения запросов. Это будет очень простой класс, независимо от вашего уровня программирования, вы поймете большую часть происходящего. Цель класса - только сохранить используемый метод, но поскольку мы находимся на классе, то добавим дополнительные функции, чтобы максимально упростить работу с библиотекой Connexus для конечного пользователя.
Начнем с создания новой папки под названием Constants, внутри нее - новый файл под названием CHttpMethod , в итоге путь будет выглядеть следующим образом: Include/Constants/HttpMethod.mqh . Внутри этого нового файла мы создадим класс CHttpMethod:
//+------------------------------------------------------------------+ //| HttpMethods.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpMethods | //| | //| [PROPERTY] | //| Name : CHttpMethods | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { public: CHttpMethod(void); ~CHttpMethod(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(void) { } //+------------------------------------------------------------------+
Чтобы содержать все возможные http-методы, давайте создадим enum, которое будет содержать все возможные методы http-запроса. Также добавим в класс новую переменную типа ENUM_HTTP_METHOD, которая называется m_method:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_HTTP_METHOD { HTTP_METHOD_NULL = 0, // [0] Null HTTP_METHOD_CONNECT, // [1] Connect HTTP_METHOD_DELETE, // [2] Delete HTTP_METHOD_GET, // [3] Get HTTP_METHOD_HEAD, // [4] Head HTTP_METHOD_OPTION, // [5] Option HTTP_METHOD_PATCH, // [6] Patch HTTP_METHOD_POST, // [7] Post HTTP_METHOD_PUT, // [8] Put HTTP_METHOD_TRACE, // [9] Trace }; //+------------------------------------------------------------------+ //| class : CHttpMethods | //| | //| [PROPERTY] | //| Name : CHttpMethods | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { private: ENUM_HTTP_METHOD m_method; // Stores the method that will be used }; //+------------------------------------------------------------------+
Теперь, когда у нас есть переменная, которая будет использоваться для хранения, давайте создадим вспомогательные методы для определения и извлечения HTTP-метода, в дополнение к перегрузке оператора = для упрощения использования основных функций:
- Оператор присваивания (operator= ): Позволяет напрямую определить HTTP-метод с помощью = operator.
- SetMethod(ENUM_HTTP_METHOD) и SetMethod(string): Определим HTTP-метод с помощью перечисления или строки. Если параметр имеет тип string, он использует функцию StringToUpper() для корректного формирования строки.
- GetMethod() и GetMethodDescription(): Получим HTTP-метод и его текстовое описание.
- void operator=(ENUM_HTTP_METHOD method): Это перегруженная операция, но, проще говоря, она используется для определения HTTP-метода с помощью оператора “=”. Вот пример применения этого оператора на практике:
CHttpMethod method; method = HTTP_METHOD_POST;
- Функции проверки (IsPost(), IsGet() и т.д.): Они облегчают проверку метода, делая код более читабельным и упрощенным. Пример того, как эти функции могут нам помочь
CHttpMethod method; method.SetMethod("POST") if(method.GetMethod() == HTTP_METHOD_POST) { //--- Action } //--- Or if(method.IsPost()) { //--- Action }
Таким образом, мы избегаем явного сравнения методов.
//+------------------------------------------------------------------+ //| class : CHttpMethod | //| | //| [PROPERTY] | //| Name : CHttpMethod | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { private: ENUM_HTTP_METHOD m_method; // Stores the method that will be used public: CHttpMethod(void); ~CHttpMethod(void); //--- Get and set void operator=(ENUM_HTTP_METHOD method); void Set(ENUM_HTTP_METHOD method); bool Set(string method); ENUM_HTTP_METHOD Get(void); string GetAsString(void); //--- Check method bool IsConnect(void); bool IsGet(void); bool IsPost(void); bool IsPut(void); bool IsDelete(void); bool IsPatch(void); bool IsHead(void); bool IsOption(void); bool IsTrace(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ void CHttpMethod::operator=(ENUM_HTTP_METHOD method) { m_method = method; } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ void CHttpMethod::Set(ENUM_HTTP_METHOD method) { m_method = method; } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ bool CHttpMethod::Set(string method) { string method_upper = method; StringToUpper(method_upper); if(method_upper == "CONNECT") { m_method = HTTP_METHOD_CONNECT; return(true); } else if(method_upper == "DELETE") { m_method = HTTP_METHOD_DELETE; return(true); } else if(method_upper == "GET") { m_method = HTTP_METHOD_GET; return(true); } else if(method_upper == "HEAD") { m_method = HTTP_METHOD_HEAD; return(true); } else if(method_upper == "OPTIONS") { m_method = HTTP_METHOD_OPTION; return(true); } else if(method_upper == "PATCH") { m_method = HTTP_METHOD_PATCH; return(true); } else if(method_upper == "POST") { m_method = HTTP_METHOD_POST; return(true); } else if(method_upper == "PUT") { m_method = HTTP_METHOD_PUT; return(true); } else if(method_upper == "TRACE") { m_method = HTTP_METHOD_TRACE; return(true); } return(false); } //+------------------------------------------------------------------+ //| Get http method | //+------------------------------------------------------------------+ ENUM_HTTP_METHOD CHttpMethod::Get(void) { return(m_method); } //+------------------------------------------------------------------+ //| Get the description of the selected http method | //+------------------------------------------------------------------+ string CHttpMethod::GetAsString(void) { switch(m_method) { case HTTP_METHOD_NULL: return "NULL"; case HTTP_METHOD_CONNECT: return "CONNECT"; case HTTP_METHOD_DELETE: return "DELETE"; case HTTP_METHOD_GET: return "GET"; case HTTP_METHOD_HEAD: return "HEAD"; case HTTP_METHOD_OPTION: return "OPTIONS"; case HTTP_METHOD_PATCH: return "PATCH"; case HTTP_METHOD_POST: return "POST"; case HTTP_METHOD_PUT: return "PUT"; case HTTP_METHOD_TRACE: return "TRACE"; default: return "Unknown HTTP Method"; } } //+------------------------------------------------------------------+ //| Check if method is connect | //+------------------------------------------------------------------+ bool CHttpMethod::IsConnect(void) { return(m_method == HTTP_METHOD_CONNECT); } //+------------------------------------------------------------------+ //| Check if method is get | //+------------------------------------------------------------------+ bool CHttpMethod::IsGet(void) { return(m_method == HTTP_METHOD_GET); } //+------------------------------------------------------------------+ //| Check if method is post | //+------------------------------------------------------------------+ bool CHttpMethod::IsPost(void) { return(m_method == HTTP_METHOD_POST); } //+------------------------------------------------------------------+ //| Check if method is put | //+------------------------------------------------------------------+ bool CHttpMethod::IsPut(void) { return(m_method == HTTP_METHOD_PUT); } //+------------------------------------------------------------------+ //| Check if method is delete | //+------------------------------------------------------------------+ bool CHttpMethod::IsDelete(void) { return(m_method == HTTP_METHOD_DELETE); } //+------------------------------------------------------------------+ //| Check if method is patch | //+------------------------------------------------------------------+ bool CHttpMethod::IsPatch(void) { return(m_method == HTTP_METHOD_PATCH); } //+------------------------------------------------------------------+ //| Check if method is head | //+------------------------------------------------------------------+ bool CHttpMethod::IsHead(void) { return(m_method == HTTP_METHOD_HEAD); } //+------------------------------------------------------------------+ //| Check if method is option | //+------------------------------------------------------------------+ bool CHttpMethod::IsOption(void) { return(m_method == HTTP_METHOD_OPTION); } //+------------------------------------------------------------------+ //| Check if method is trace | //+------------------------------------------------------------------+ bool CHttpMethod::IsTrace(void) { return(m_method == HTTP_METHOD_TRACE); } //+------------------------------------------------------------------+
На этом завершается класс, ответственный за хранение используемого HTTP-метода. У нас есть несколько вспомогательных функций для сохранения некоторого кода в будущем. Перейдем к следующему вспомогательному классу.
Код состояния
Коды состояния, проще говоря, представляют собой цифры. Эта цифра стандартизирована и отправляется сервером клиенту после обработки запроса. Каждый код состоит из трех цифр, первая из которых указывает на категорию, к которой относится статус (1xx, 2xx, 3xx, 4xx и 5xx). Этот код просто сообщает вам, каков был результат запроса, был ли он успешно выполнен, была ли сгенерирована ошибка на стороне сервера или запрос был отправлен некорректно. Существует несколько кодов состояния. Это число может варьироваться от 100 до 599, и они разделены на 5 категорий. Чтобы узнать, к какой категории относится код, просто определите, в каком диапазоне он находится, смотрите таблицу со значениями:
Код состояния диапазона | Описание |
---|---|
100-199 | Это не так уж часто можно увидеть. Это ответы типа "Я обрабатываю, подождите". Это сервер сообщает, что работает над вашим запросом, но он еще не завершен. |
200-299 | Ах, вот ответ, который нам нравится больше всего! Это значит, что все прошло хорошо. Самым известным из них является 200 OK – знак того, что “все прошло хорошо”. Вы просили об этом - доставлено. Все просто. |
300-399 | Сервер, по сути, говорит вам: “Ой, вы не в том месте, идите туда”. 301 “Перемещено навсегда” – это постоянное перенаправление, в то время как 302 "Найдено" - временное, что-то вроде: "Я на ремонте, но пока вы можете найти это здесь». |
400-499 | Это печально известные ошибки, которые мы, как пользователи, часто допускаем. Наиболее известным является 404 "Не найдено", когда страница, которую вы ищете, просто не существует. Это все равно что прийти по нужному адресу и обнаружить, что здание снесено. |
500-599 | Теперь, когда проблема возникает на другой стороне, вина ложится на сервер. Знаменитая внутренняя ошибка сервера 500 - это, по сути, когда сервер разводит руками и говорит: “здесь что-то пошло не так”. |
Существует несколько возможных кодов. Я не буду описывать их все, чтобы не делать статью слишком длинной. Если вы хотите узнать больше обо всех возможных значениях, прочитайте здесь, здесь подробно объясняется каждый возможный код. Если вы хотите узнать больше о протоколе HTTP, это стоит прочитать. В повседневной жизни разработчика используется всего несколько кодов, и большинство из них редко можно найти в Интернете. Перечислю наиболее общие:
1xx: Информационный
- 100 Continue: Сервер получил заголовки, и клиент может продолжить отправку тела запроса.
- 101 Switching Protocols: Клиент запросил изменение протокола, и сервер принял его.
2xx: Успешно
- 200 OK: Запрос выполнен успешно.
- 201 Created: Запрос выполнен успешно и создан новый ресурс. - 204 No Content: Запрос выполнен успешно, но в тексте ответа нет содержимого.
3xx: Перенаправление
- 301 Moved Permanently: Ресурс был окончательно перемещен на новый URL-адрес.
- 302 Found: Ресурс временно перемещен по новому URL-адресу.
- 304 Not Modified: Ресурс не был изменен с момента последнего запроса, что позволяет клиенту использовать кэшированную версию.
4xx: Ошибки клиента
- 400 Bad Request: Запрос недействителен или неправильно сформирован.
- 401 Unauthorized: Доступ не авторизован; требуется аутентификация.
- 403 Forbidden: Сервер понял запрос, но отказывает в доступе.
- 404 Not Found: Запрашиваемый ресурс не найден.
- 405 Method Not Allowed: Используемый HTTP-метод запрещен для запрашиваемого ресурса.
5xx: Ошибки сервера
- 500 Internal Server Error: На сервере произошла общая ошибка.
- 502 Bad Gateway: Сервер получил неверный ответ при попытке выполнить запрос.
- 503 Service Unavailable: Сервер временно недоступен, как правило, из-за перегрузки или технического обслуживания.
- 504 Gateway Timeout: Сервер не получил вовремя ответа от другого сервера, к которому пытался подключиться.
Теперь, когда мы разобрались со всеми категориями статусов и наиболее часто используемыми из них, я хочу, чтобы библиотека поддерживала все возможные статусы. Для этого мы будем работать над классом, способным обрабатывать любой код состояния, полученный сервером, при условии, что он действителен.
Создание класса CHttpStatusCode
Теперь, когда мы знаем все возможные коды состояния, давайте добавим соответствующую реализацию в библиотеку. Цель здесь проста: создать класс, который будет отвечать за хранение полученного кода состояния. Класс также должен содержать поддержку для описания каждого статуса, а также должна быть возможность быстро определить, к какой категории относится этот статус.
Перейдём к коду. В этой же папке, ранее созданной для класса CHttpMethod, мы создадим новый файл с именем HttpStatusCode.mqh . В конце концов, полный путь будет следующим: Includes/Connexus/Constants/HttpStatusCode.mqh .
//+------------------------------------------------------------------+ //| HttpStatusCode.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+
Чтобы содержать все возможные коды состояния, мы создадим перечисление (enum) со всеми возможными значениями. Именем перечисления будет ENUM_HTTP_STATUS, значением перечисления будет соответствующий код состояния.
enum ENUM_HTTP_STATUS { //--- Mql error HTTP_STATUS_URL_NOT_ALLOWED = -1, HTTP_STATUS_URL_NOT_DEFINED = 1, HTTP_STATUS_METHOD_NOT_DEFINED = 2, //--- Informational HTTP_STATUS_CONTINUE = 100, HTTP_STATUS_SWITCHING_PROTOCOLS = 101, HTTP_STATUS_PROCESSING = 102, HTTP_STATUS_EARLY_HINTS = 103, //--- Successul HTTP_STATUS_OK = 200, HTTP_STATUS_CREATED = 201, HTTP_STATUS_ACCEPTED = 202, HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, HTTP_STATUS_NO_CONTENT = 204, HTTP_STATUS_RESET_CONTENT = 205, HTTP_STATUS_PARTIAL_CONTENT = 206, HTTP_STATUS_MULTI_STATUS = 207, HTTP_STATUS_ALREADY_REPORTED = 208, //--- Redirection messages HTTP_STATUS_MULTIPLE_CHOICES = 300, HTTP_STATUS_MOVED_PERMANENTLY = 301, HTTP_STATUS_FOUND = 302, HTTP_STATUS_SEE_OTHER = 303, HTTP_STATUS_NOT_MODIFIED = 304, HTTP_STATUS_USE_PROXY = 305, HTTP_STATUS_SWITCH_PROXY = 306, HTTP_STATUS_TEMPORARY_REDIRECT = 307, HTTP_STATUS_PERMANENT_REDIRECT = 308, //--- Client error HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_UNAUTHORIZED = 401, HTTP_STATUS_PAYMENT_REQUIRED = 402, HTTP_STATUS_FORBIDDEN = 403, HTTP_STATUS_NOT_FOUND = 404, HTTP_STATUS_METHOD_NOT_ALLOWED = 405, HTTP_STATUS_NOT_ACCEPTABLE = 406, HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, HTTP_STATUS_REQUEST_TIMEOUT = 408, HTTP_STATUS_CONFLICT = 409, HTTP_STATUS_GONE = 410, HTTP_STATUS_LENGTH_REQUIRED = 411, HTTP_STATUS_PRECONDITION_FAILED = 412, HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, HTTP_STATUS_URI_TOO_LONG = 414, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, HTTP_STATUS_EXPECTATION_FAILED = 417, HTTP_STATUS_MISDIRECTED_REQUEST = 421, HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, HTTP_STATUS_LOCKED = 423, HTTP_STATUS_FAILED_DEPENDENCY = 424, HTTP_STATUS_TOO_EARLY = 425, HTTP_STATUS_UPGRADE_REQUIRED = 426, HTTP_STATUS_PRECONDITION_REQUIRED = 428, HTTP_STATUS_TOO_MANY_REQUESTS = 429, HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, //--- Server error HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, HTTP_STATUS_NOT_IMPLEMENTED = 501, HTTP_STATUS_BAD_GATEWAY = 502, HTTP_STATUS_SERVICE_UNAVAILABLE = 503, HTTP_STATUS_GATEWAY_TIMEOUT = 504, HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, HTTP_STATUS_INSUFFICIENT_STORAGE = 507, HTTP_STATUS_LOOP_DETECTED = 508, HTTP_STATUS_NOT_EXTENDED = 510, HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511 };
Обратите внимание, что я добавил несколько комментариев, разделяющих категории каждого статуса. Обратите внимание на первые значения перечисления, я добавил эти значения как “пользовательский код состояния”, который будет автоматически сгенерирован библиотекой, это:
- HTTP_STATUS_URL_NOT_ALLOWED: URL-адрес не был добавлен в список разрешенных URL-адресов в терминале
- HTTP_STATUS_URL_NOT_DEFINED: URL-адрес не был определен в запросе
- HTTP_STATUS_METHOD_NOT_DEFINED: Для запроса не был определен допустимый метод
Когда вызывается функция WebRequest и возвращает значение -1, это означает, что URL-адрес не добавлен в терминал, как указано в документации по MQL5, поэтому библиотека должна автоматически возвращать HTTP_STATUS_URL_NOT_ALLOWED . Аналогичная логика будет применена и к другим пользовательским кодам, но сейчас мы не будем заострять на этом внимание.
Продолжим разработку класса, этот класс будет похож на CHttpMethod, мы добавим новую частную переменную с именем m_status типа ENUM_HTTP_STATUS, а также добавим несколько вспомогательных методов для установки и получения значения этой переменной:
- operator=(int) и operator=(ENUM_HTTP_STATUS): Устанавливают значение m_status с помощью оператора =, получив целое число или перечислимое значение.
- Set(ENUM_HTTP_STATUS): Устанавливает код состояния, используя перечислимое значение.
- Get() и GetMessage(): Возвращает текущий код состояния или только сообщение, соответствующее сохраненному коду.
Ниже приведен код с реализацией этих методов:
//+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { private: ENUM_HTTP_STATUS m_status; // Stores the status used public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); //--- Set void operator=(int status); void operator=(ENUM_HTTP_STATUS status); void Set(ENUM_HTTP_STATUS status); //--- Get ENUM_HTTP_STATUS Get(void); string GetMessage(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Assignment operator to set status from integer value | //+------------------------------------------------------------------+ void CHttpStatusCodes::operator=(int status) { m_status = (ENUM_HTTP_STATUS)status; } //+------------------------------------------------------------------+ //| Assignment operator to set status from ENUM_HTTP_STATUS | //+------------------------------------------------------------------+ void CHttpStatusCodes::operator=(ENUM_HTTP_STATUS status) { m_status = status; } //+------------------------------------------------------------------+ //| Sets the HTTP status code | //+------------------------------------------------------------------+ void CHttpStatusCodes::Set(ENUM_HTTP_STATUS status) { m_status = status; } //+------------------------------------------------------------------+ //| Returns the stored HTTP status code | //+------------------------------------------------------------------+ ENUM_HTTP_STATUS CHttpStatusCodes::Get(void) { return(m_status); } //+------------------------------------------------------------------+ //| Returns a message corresponding to the stored HTTP status code | //+------------------------------------------------------------------+ string CHttpStatusCodes::GetMessage(void) { switch(m_status) { case HTTP_STATUS_URL_NOT_ALLOWED: return "The URL was not added to the list of allowed URLs in the terminal"; case HTTP_STATUS_URL_NOT_DEFINED: return "URL was not defined in the request"; case HTTP_STATUS_METHOD_NOT_DEFINED: return "Method was not defined in the request"; case HTTP_STATUS_CONTINUE: return "Continue"; case HTTP_STATUS_SWITCHING_PROTOCOLS: return "Switching Protocols"; case HTTP_STATUS_PROCESSING: return "Processing"; case HTTP_STATUS_EARLY_HINTS: return "Early Hints"; case HTTP_STATUS_OK: return "OK"; case HTTP_STATUS_CREATED: return "Created"; case HTTP_STATUS_ACCEPTED: return "Accepted"; case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information"; case HTTP_STATUS_NO_CONTENT: return "No Content"; case HTTP_STATUS_RESET_CONTENT: return "Reset Content"; case HTTP_STATUS_PARTIAL_CONTENT: return "Partial Content"; case HTTP_STATUS_MULTI_STATUS: return "Multi-Status"; case HTTP_STATUS_ALREADY_REPORTED: return "Already Reported"; case HTTP_STATUS_MULTIPLE_CHOICES: return "Multiple Choices"; case HTTP_STATUS_MOVED_PERMANENTLY: return "Moved Permanently"; case HTTP_STATUS_FOUND: return "Found"; case HTTP_STATUS_SEE_OTHER: return "See Other"; case HTTP_STATUS_NOT_MODIFIED: return "Not Modified"; case HTTP_STATUS_USE_PROXY: return "Use Proxy"; case HTTP_STATUS_SWITCH_PROXY: return "Switch Proxy"; case HTTP_STATUS_TEMPORARY_REDIRECT: return "Temporary Redirect"; case HTTP_STATUS_PERMANENT_REDIRECT: return "Permanent Redirect"; case HTTP_STATUS_BAD_REQUEST: return "Bad Request"; case HTTP_STATUS_UNAUTHORIZED: return "Unauthorized"; case HTTP_STATUS_PAYMENT_REQUIRED: return "Payment Required"; case HTTP_STATUS_FORBIDDEN: return "Forbidden"; case HTTP_STATUS_NOT_FOUND: return "Not Found"; case HTTP_STATUS_METHOD_NOT_ALLOWED: return "Method Not Allowed"; case HTTP_STATUS_NOT_ACCEPTABLE: return "Not Acceptable"; case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required"; case HTTP_STATUS_REQUEST_TIMEOUT: return "Request Timeout"; case HTTP_STATUS_CONFLICT: return "Conflict"; case HTTP_STATUS_GONE: return "Gone"; case HTTP_STATUS_LENGTH_REQUIRED: return "Length Required"; case HTTP_STATUS_PRECONDITION_FAILED: return "Precondition Failed"; case HTTP_STATUS_PAYLOAD_TOO_LARGE: return "Payload Too Large"; case HTTP_STATUS_URI_TOO_LONG: return "URI Too Long"; case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type"; case HTTP_STATUS_RANGE_NOT_SATISFIABLE: return "Range Not Satisfiable"; case HTTP_STATUS_EXPECTATION_FAILED: return "Expectation Failed"; case HTTP_STATUS_MISDIRECTED_REQUEST: return "Misdirected Request"; case HTTP_STATUS_UNPROCESSABLE_ENTITY: return "Unprocessable Entity"; case HTTP_STATUS_LOCKED: return "Locked"; case HTTP_STATUS_FAILED_DEPENDENCY: return "Failed Dependency"; case HTTP_STATUS_TOO_EARLY: return "Too Early"; case HTTP_STATUS_UPGRADE_REQUIRED: return "Upgrade Required"; case HTTP_STATUS_PRECONDITION_REQUIRED: return "Precondition Required"; case HTTP_STATUS_TOO_MANY_REQUESTS: return "Too Many Requests"; case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: return "Request Header Fields Too Large"; case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: return "Unavailable For Legal Reasons"; case HTTP_STATUS_INTERNAL_SERVER_ERROR: return "Internal Server Error"; case HTTP_STATUS_NOT_IMPLEMENTED: return "Not Implemented"; case HTTP_STATUS_BAD_GATEWAY: return "Bad Gateway"; case HTTP_STATUS_SERVICE_UNAVAILABLE: return "Service Unavailable"; case HTTP_STATUS_GATEWAY_TIMEOUT: return "Gateway Timeout"; case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported"; case HTTP_STATUS_VARIANT_ALSO_NEGOTIATES: return "Variant Also Negotiates"; case HTTP_STATUS_INSUFFICIENT_STORAGE: return "Insufficient Storage"; case HTTP_STATUS_LOOP_DETECTED: return "Loop Detected"; case HTTP_STATUS_NOT_EXTENDED: return "Not Extended"; case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED: return "Network Authentication Required"; default: return "Unknown HTTP Status"; } } //+------------------------------------------------------------------+
Добавим еще несколько вспомогательных методов, которые будут отвечать за проверку того, относится ли код состояния, хранящийся в классе, к определенной категории, это:
- bool IsInformational(void): Информационный диапазон (100 - 199)
- bool IsSuccess(void): Диапазон успеха (200 - 299)
- bool IsRedirection(void): Диапазон перенаправления (300 - 399)
- bool IsClientError(void): Диапазон ошибок клиента (400 - 499)
- bool IsServerError(void): Диапазон ошибок сервера (500 - 599)
//+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { private: ENUM_HTTP_STATUS m_status; // Stores the status used public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); //--- Check which group the code is in bool IsInformational(void); // Checks if the status code is in the informational response range (100 - 199) bool IsSuccess(void); // Check if the status code is in the success range (200 - 299) bool IsRedirection(void); // Check if the status code is in the redirect range (300 - 399) bool IsClientError(void); // Checks if the status code is in the client error range (400 - 499) bool IsServerError(void); // Check if the status code is in the server error range (500 - 599) }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Checks if the status code is in the informational response | //| range (100 - 199) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsInformational(void) { return(m_status >= 100 && m_status <= 199); } //+------------------------------------------------------------------+ //| Check if the status code is in the success range (200 - 299) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsSuccess(void) { return(m_status >= 200 && m_status <= 299); } //+------------------------------------------------------------------+ //| Check if the status code is in the redirect range (300 - 399) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsRedirection(void) { return(m_status >= 300 && m_status <= 399); } //+------------------------------------------------------------------+ //| Checks if the status code is in the client error range | //| (400 - 499) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsClientError(void) { return(m_status >= 400 && m_status <= 499); } //+------------------------------------------------------------------+ //| Check if the status code is in the server error range (500 - 599)| //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsServerError(void) { return(m_status >= 500 && m_status <= 599); } //+------------------------------------------------------------------+
Заключение
Чтобы сделать работу библиотеки более наглядной, следуйте приведенной ниже схеме:
У нас уже готовы все вспомогательные классы, отвечающие за независимую обработку каждого HTTP-элемента. У нас есть классы CQueryParam , CHttpHeader и CHttpBody, использующие класс CJson, но между ними нет отношения наследования. Классы, созданные в настоящей статье, еще не подключены к другим, в следующей статье мы подключим все, создав HTTP-запрос и ответ.
В настоящей статье мы разбираемся с методами HTTP и кодами состояния, двумя очень важными элементами взаимодействия между клиентом и сервером в Интернете. Понимание того, что каждый метод действительно дает возможность более точно делать запросы, информируя сервер о том, какое действие надо выполнить, и делая его более эффективным. Каждый метод играет определенную роль в коммуникации, и его правильное использование делает взаимодействие с API более понятным, как для клиента, так и для сервера, без неожиданностей.
Кроме того, мы говорим о кодах состояния, которые являются прямым ответом сервера о том, что произошло с запросом. Они варьируются от простого “все в порядке” (200 ОК) до сообщений об ошибках на стороне клиента (4xx) или сервера (5xx). Знание того, как обращаться с этими кодами, является ценным навыком, поскольку часто ошибка означает не завершение линии, а скорее возможность скорректировать или повторить попытку.
В процессе создания библиотеки Connexus мы узнали, как обращаться с каждым из этих элементов, что делает нашу библиотеку более надежной и способной обрабатывать нюансы HTTP-взаимодействия. С этого момента наш класс, отвечающий за методы и коды состояния, будет готов предоставить разработчику более высокий уровень контроля и безопасности при взаимодействии с API.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16136





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования