English Deutsch 日本語
preview
Помощник Connexus (Часть 5): HTTP-методы и коды состояния

Помощник Connexus (Часть 5): HTTP-методы и коды состояния

MetaTrader 5Примеры | 4 июня 2025, 07:52
160 0
joaopedrodev
joaopedrodev

Введение

Данная статья является продолжением серии статей, в которых мы будем создавать библиотеку под названием 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);
  }
//+------------------------------------------------------------------+


Заключение

Чтобы сделать работу библиотеки более наглядной, следуйте приведенной ниже схеме:

Diagram

У нас уже готовы все вспомогательные классы, отвечающие за независимую обработку каждого HTTP-элемента. У нас есть классы CQueryParam , CHttpHeader и CHttpBody, использующие класс CJson, но между ними нет отношения наследования. Классы, созданные в настоящей статье, еще не подключены к другим, в следующей статье мы подключим все, создав HTTP-запрос и ответ.

В настоящей статье мы разбираемся с методами HTTP и кодами состояния, двумя очень важными элементами взаимодействия между клиентом и сервером в Интернете. Понимание того, что каждый метод действительно дает возможность более точно делать запросы, информируя сервер о том, какое действие надо выполнить, и делая его более эффективным. Каждый метод играет определенную роль в коммуникации, и его правильное использование делает взаимодействие с API более понятным, как для клиента, так и для сервера, без неожиданностей.

Кроме того, мы говорим о кодах состояния, которые являются прямым ответом сервера о том, что произошло с запросом. Они варьируются от простого “все в порядке” (200 ОК) до сообщений об ошибках на стороне клиента (4xx) или сервера (5xx). Знание того, как обращаться с этими кодами, является ценным навыком, поскольку часто ошибка означает не завершение линии, а скорее возможность скорректировать или повторить попытку.

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

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16136

Разрабатываем мультивалютный советник (Часть 27): Компонент для вывода многострочного текста Разрабатываем мультивалютный советник (Часть 27): Компонент для вывода многострочного текста
При возникновении необходимости вывести текстовую информацию на график мы можем воспользоваться функцией Comment(). Но её возможности достаточно сильно ограничены. Поэтому, в рамках этой статьи, мы создадим собственный компонент — диалоговое окно на весь экран, способное выводить многострочный текст с гибкими настройками шрифта и поддержкой прокрутки.
От начального до среднего уровня: Объединение (II) От начального до среднего уровня: Объединение (II)
Сегодня нас ждет очень забавная и довольно интересная статья, причем в нескольких аспектах. В ней мы рассмотрим объединение, чтобы решить проблему, о которой говорилось ранее. Кроме того, мы изучим некоторые необычные ситуации, которые могут возникнуть при использовании объединения в приложениях. Представленные здесь материалы предназначены исключительно для образовательных целей. Ни в коем случае нельзя рассматривать приложение ни с какой иной целью, кроме как для изучения и освоения представленных концепций.
Изучаем конформное прогнозирование финансовых временных рядов Изучаем конформное прогнозирование финансовых временных рядов
В этой статье вы познакомитесь с конформными предсказаниями и библиотекой MAPIE, которая их реализует. Данный подход является одним из самых современных в машинном обучении и позволяет сосредоточиться на контроле рисков для уже существующих разнообразных моделей машинного обучения. Конформные предсказания, сами по себе, не являются способом поиска закономерностей в данных. Они лишь определяют степень уверенности существующих моделей в предсказании конкретных примеров и позволяют фильтровать надежные предсказания.
Криптография в MQL5: Шифрование, хеширование и защита данных Криптография в MQL5: Шифрование, хеширование и защита данных
В данной статье рассматривается интеграция криптографии в MQL5 с целью повышения безопасности и функциональности торговых алгоритмов. Мы рассмотрим основные методы криптографии и реализуем их в автоматической торговле.