
Отправка запросов в Connexus (Часть 6): Создание HTTP-запроса и ответа
Введение
Данная статья является частью продолжающейся серии статей, в которых мы создаем библиотеку под названием Connexus. В первой статье мы рассмотрели основные функциональные возможности функции WebRequest, разобравшись с каждым из ее параметров и создав пример кода, демонстрирующий ее использование и связанные с ним трудности. В предыдущей статье мы рассмотрели, что такое HTTP-методы и коды состояния, возвращаемые сервером, указывающие на то, был ли запрос успешно обработан или произошла ошибка на стороне клиента или сервера.
В этой шестой статье из серии о библиотеке Connexus мы сосредоточимся на полном HTTP-запросе, рассмотрев каждый компонент, из которого состоит запрос. Мы создадим класс, представляющий запрос в целом, который поможет нам объединить ранее созданные классы. Кроме того, мы разработаем аналогичный класс для обработки ответа сервера, содержащий данные ответа, код состояния и даже продолжительность запроса.
При передаче данных по протоколу HTTP запрос состоит из нескольких компонентов, которые вместе образуют полный запрос. Мы уже изучали все эти компоненты в предыдущих статьях и создали индивидуальные классы для каждого элемента запроса. Давайте кратко рассмотрим приведенные ниже элементы:
- URL: Определяет адрес сервера в Интернете и состоит из более мелких частей, таких как домен, порт, путь и т.д. Более подробно это было рассмотрено в Части 2 Connexus, где мы создали класс для правильного форматирования URL.
- Заголовок: Это дополнительные данные, отправляемые вместе с запросом, предназначенные для предоставления подробной информации о запросе, которая не является частью основного текста или URL-адреса. Более подробно это было рассмотрено в Части 3 Connexus, где мы также создали класс, отвечающий за организацию заголовка запроса.
- Тело: Относится к фактическому содержимому, которое отправляется или принимается. Проще говоря, тело - это место, где хранятся интересующие нас данные, которые мы хотим отправить на сервер. В Части 4 мы обсуждали это более подробно, а также создали класс, отвечающий за хранение тела запроса, который поддерживает добавление тела в различных форматах, таких как обычный текст (строка), JSON или char[] (двоичный).
- Метод HTTP: HTTP-методы используются клиентом для того, чтобы сообщить серверу, какое действие тот собирается выполнить. Более подробно это было рассмотрено в Части 5 Connexus.
- Таймаут: Таймаут не рассматривался в предыдущих статьях, но если вкратце, то это время в миллисекундах, необходимое серверу для ответа. Если запрос выполняется дольше отведенного времени, он завершается, что приводит к ошибке таймаута. Это значение может быть полезно, чтобы избежать сценариев, когда серверу требуется слишком много времени для ответа, поскольку функция WebRequest является синхронной, что означает, что советник остается "приостановленным" в ожидании ответа сервера. Это может быть проблематично, если выполнение запроса займет гораздо больше времени, чем ожидалось. Чтобы избежать этого сценария, рекомендуется использовать таймаут. Значение таймаута может варьироваться в зависимости от ваших потребностей, но для корректной обработки запроса большинству серверов достаточно 5000 миллисекунд (5 секунд).
Каждый из этих компонентов играет фундаментальную роль в построении правильного HTTP-запроса, но важно отметить, что не все из них являются обязательными. Единственными обязательными элементами являются URL и HTTP-метод (GET, POST, PUT и т.д.).
Чтобы помочь нам сориентироваться в ходе работы над библиотекой и классами, которые мы уже создали, давайте взглянем на текущую схему библиотеки:
Обратите внимание, что у нас уже есть классы, готовые обрабатывать HTTP-методы, коды состояния, URL-адреса с параметрами запроса, заголовки и тело.
Паттерн проектирования Facade
Чтобы продолжить создание библиотеки, мы реализуем паттерн проектирования. Если вы не знакомы с паттернами проектирования, рекомендую прочитать серию статей Паттерны проектирования при разработке программного обеспечения и MQL5, написанных Мохаммедом Абдельмаабудом (Mohamed Abdelmaaboud). В этой серии автор описывает несколько паттернов проектирования с примерами кода. Для библиотеки Connexus мы реализуем паттерн проектирования "Facade", который является хорошо известным паттерном в программировании. Этот паттерн обеспечивает упрощенный интерфейс к более сложному набору подсистем, скрывая внутреннюю сложность и позволяя клиенту взаимодействовать с системой гораздо более простым способом.
Давайте представим пример в контексте библиотеки: вы хотите создать запрос. Для этого вам нужно будет создать экземпляр каждого из элементов запроса и настроить их, примерно так:
CURL m_url; m_url.Parse("http://example.com/api"); CHttpBody m_body; m_body.AddString("my text"); CHttpHeader m_headers; m_headers.Add("content-type","text/plain"); CHttpMethod m_method; m_method = HTTP_METHOD_GET; int m_timeout = 5000;
Такой подход загромождает код, требуя создания нескольких экземпляров, занимая много строк и делая код менее читабельным. Ситуация ухудшается при работе с большим количеством запросов, поскольку управление несколькими объектами, такими как заголовки, тело и URL-адрес, становится сложным и труднодоступным для поддержания. Именно теперь и вступает в игру наше проектирование Facade. Возвращаясь к концепции: Этот паттерн обеспечивает упрощенный интерфейс к более сложному набору подсистем, скрывая внутреннюю сложность и позволяя клиенту взаимодействовать с системой гораздо более простым способом.
В этом контексте подсистемы являются классами для элементов запроса, таких как CHttpBody , CHttpHeaders и т.д., и цель состоит в том, чтобы создать для них более интуитивно понятный интерфейс. Этот паттерн решает проблему, вводя класс или интерфейс, который действует как «Фасад" для доступа к подсистемам. Конечный разработчик взаимодействует только с этим упрощенным интерфейсом.
Таким образом, архитектура Facade обладает следующими преимуществами:
- Упрощенное взаимодействие: Вместо того чтобы напрямую работать с рядом сложных классов, разработчик может использовать упрощенный интерфейс, который скрывает внутренние детали.
- Пониженная связь: Поскольку клиент напрямую не связан с внутренними подсистемами, изменения в этих подсистемах могут быть внесены без ущерба для клиента.
- Улучшенная обслуживаемость: Четкое разделение между интерфейсом Facade и внутренними подсистемами упрощает поддержку и расширение кода, поскольку любые внутренние изменения могут быть абстрагированы с помощью "facade".
Как этот паттерн проектирования был бы реализован в библиотеке? Для этого создадим новый класс под названием CHttpRequest, который будет содержать подсистемы. Для пользователя библиотеки использование этого класса должно выглядеть примерно так:
CHttpRequest request; request.Method() = HTTP_METHOD_GET; request.Url().Parse("http://example.com/api"); request.Body().AddString("my text"); request.Header().Add("content-type","text/plain");
Обратите внимание, что код стал намного проще и удобочитаемее, что как раз и является идеей, лежащей в основе этого паттерна проектирования. Паттерн Facade обеспечивает упрощенный интерфейс (CHttpRequest) к более сложному набору подсистем (управляя экземплярами CHttpBody, CHttpHeader и т.д.), скрывая внутреннюю сложность и позволяя клиенту взаимодействовать с системой гораздо более простым способом.
Создание класса CHttpRequest
Теперь, когда мы понимаем концепцию Facade, мы можем применить эту архитектуру к классу CHttpRequest. Давайте создадим этот класс в новой папке под названием core. Файл будет называться HttpRequest.mqh, а конечный путь будет: Include/Connexus/Core/HttpRequest.mqh. Первоначально файл будет выглядеть так://+------------------------------------------------------------------+ //| HttpRequest.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpRequest | //| | //| [PROPERTY] | //| Name : CHttpRequest | //| Heritage : No heritage | //| Description : Gathers elements of an http request such as url, | //| body, header, method and timeout | //| | //+------------------------------------------------------------------+ class CHttpRequest { public: CHttpRequest(void); ~CHttpRequest(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpRequest::CHttpRequest(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpRequest::~CHttpRequest(void) { } //+------------------------------------------------------------------+
Давайте импортируем классы, созданные в последних файлах: CURL, CHttpBody, CHttpHeader и CHttpMethod. Мы создадим экземпляр каждого из них, добавив "*", чтобы сообщить компилятору, что мы будем управлять указателем вручную. Кроме того, мы добавим переменную с именем m_timeout типа int, которая будет хранить значение таймаута для запроса.
//+------------------------------------------------------------------+ //| HttpRequest.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "../URL/URL.mqh" #include "../Header/HttpBody.mqh" #include "../Header/HttpHeader.mqh" #include "../Constants/HttpMethod.mqh" //+------------------------------------------------------------------+ //| class : CHttpRequest | //| | //| [PROPERTY] | //| Name : CHttpRequest | //| Heritage : No heritage | //| Description : Gathers elements of an http request such as url, | //| body, header, method and timeout | //| | //+------------------------------------------------------------------+ class CHttpRequest { private: CURL *m_url; CHttpBody *m_body; CHttpHeader *m_headers; CHttpMethod *m_method; int m_timeout; public: CHttpRequest(void); ~CHttpRequest(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpRequest::CHttpRequest(void) { m_url = new CURL(); m_body = new CHttpBody(); m_headers = new CHttpHeader(); m_method = new CHttpMethod(); m_timeout = 5000; // Default timeout (5 seconds) } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpRequest::~CHttpRequest(void) { delete m_url; delete m_body; delete m_headers; delete m_method; } //+------------------------------------------------------------------+
Теперь добавим несколько методов для доступа к указателю для каждого экземпляра, а также методы для установки и получения значения тайм-аута:
- CURL *Url(void) : Возвращает указатель на URL-адрес
- CHttpBody *Body(void) : Возвращает указатель на тело
- CHttpHeader *Header(void) : Возвращает указатель на заголовок
- CHttpMethod *Method(void) : Возвращает указатель на метод
- CHttpRequest *Timeout(int timeout) : Устанавливает таймаут
- int Timeout(void) : Получает таймаут
В дополнение к этим методам добавим несколько вспомогательных методов:
-
void Clear(void) : Удаляет все данные из экземпляров
-
string FormatString(void) : Генерирует строку, содержащую все данные запроса
Пример отформатированного запроса:
HTTP Request: --------------- Method: GET URL: https://api.example.com/resource?id=123&filter=active Headers: --------------- Authorization: Bearer token Content-Type: application/json User-Agent: MyHttpClient/1.0 Body: --------------- { "key": "value", "data": [1, 2, 3] } ---------------
Вот реализация этих методов.
//+------------------------------------------------------------------+ //| HttpRequest.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpRequest | //| | //| [PROPERTY] | //| Name : CHttpRequest | //| Heritage : No heritage | //| Description : Gathers elements of an http request such as url, | //| body, header, method and timeout | //| | //+------------------------------------------------------------------+ class CHttpRequest { public: //--- HTTP CURL *Url(void); // Get url object CHttpBody *Body(void); // Get body object CHttpHeader *Header(void); // Get header object CHttpMethod *Method(void); // Get method object //--- Timeout CHttpRequest *Timeout(int timeout); // Set timeout int Timeout(void); // Get timeout //--- Auxiliary methods void Clear(void); // Reset data string FormatString(void); // Format data }; //+------------------------------------------------------------------+ //| Get url object | //+------------------------------------------------------------------+ CURL *CHttpRequest::Url(void) { return(GetPointer(m_url)); } //+------------------------------------------------------------------+ //| Get body object | //+------------------------------------------------------------------+ CHttpBody *CHttpRequest::Body(void) { return(GetPointer(m_body)); } //+------------------------------------------------------------------+ //| Get header object | //+------------------------------------------------------------------+ CHttpHeader *CHttpRequest::Header(void) { return(GetPointer(m_headers)); } //+------------------------------------------------------------------+ //| Get method object | //+------------------------------------------------------------------+ CHttpMethod *CHttpRequest::Method(void) { return(GetPointer(m_method)); } //+------------------------------------------------------------------+ //| Set timeout | //+------------------------------------------------------------------+ CHttpRequest *CHttpRequest::Timeout(int timeout) { m_timeout = timeout; return(GetPointer(this)); } //+------------------------------------------------------------------+ //| Get timeout | //+------------------------------------------------------------------+ int CHttpRequest::Timeout(void) { return(m_timeout); } //+------------------------------------------------------------------+ //| Reset data | //+------------------------------------------------------------------+ void CHttpRequest::Clear(void) { m_url.Clear(); m_body.Clear(); m_headers.Clear(); m_timeout = 5000; } //+------------------------------------------------------------------+ //| Format data | //+------------------------------------------------------------------+ string CHttpRequest::FormatString(void) { return( "HTTP Request:"+ "\n---------------"+ "\nMethod: "+m_method.GetMethodDescription()+ "\nURL: "+m_url.FullUrl()+ "\n"+ "\n---------------"+ "\nHeaders:"+ "\n"+m_headers.Serialize()+ "\n"+ "\n---------------"+ "\nBody:"+ "\n"+m_body.GetAsString()+ "\n---------------" ); } //+------------------------------------------------------------------+
Таким образом, мы завершили работу над этим классом, который служит фасадом для доступа к объектам, формирующим HTTP-запрос. Важно отметить, что я добавляю только те части, которые были изменены в коде. Полный файл можно найти в конце прикрепленной статьи.
С этим новым классом CHttpRequest обновленная схема библиотеки выглядит следующим образом:
Вкратце, CHttpRequest действует как фасад, упрощая процесс настройки и отправки HTTP-запроса. Внутренне класс CHttpHeaders обрабатывает логику заголовка, в то время как CHttpBody заботится о создании тела запроса. Разработчику, использующему эту библиотеку, не нужно беспокоиться о деталях обработки заголовков или основного текста – они просто устанавливают значения с использованием методов CHttpRequest, а класс facade позаботится обо всем остальном.
Создание класса CHttpResponse
Следуя той же идее, давайте создадим еще один класс, который будет использоваться для представления данных ответа сервера. Он будет следовать структуре, аналогичной CHttpRequest. Это те элементы, которые формируют ответ:
- Заголовок: Как и запрос, ответ также содержит заголовок, который информирует клиента с помощью метаданных о запросе.
- Тело: Будет содержать текст ответа сервера. Именно сюда сервер отправляет данные, которые мы хотим получить, и это суть сообщения.
- Код состояния: Содержит код состояния, который мы более подробно обсуждали в Части 5 настоящей серии. Этот код представляет собой 3-значное число, которое сообщает, был ли запрос успешно обработан или произошла ошибка со стороны клиента или сервера.
- Длительность: Сохраняет время, затраченное на выполнение запроса, измеряемое в миллисекундах.
Мы создадим новый файл в папке core под названием HttpResponse, а окончательный путь к нему будет следующим: Include/Connexus/Core/HttpResponse.mqh . Созданный класс должен выглядеть следующим образом:
//+------------------------------------------------------------------+ //| HttpResponse.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpResponse | //| | //| [PROPERTY] | //| Name : CHttpResponse | //| Heritage : No heritage | //| Description : gathers elements of an http response such as body, | //| header, status code and duration | //| | //+------------------------------------------------------------------+ class CHttpResponse { public: CHttpResponse(void); ~CHttpResponse(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpResponse::CHttpResponse(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpResponse::~CHttpResponse(void) { } //+------------------------------------------------------------------+
Мы импортируем элементы ответа, а именно: CHttpHeader, CHttpBody и CHttpStatusCode. После этого создадим экземпляр каждого из этих классов, а также частную переменную типа ulong, в которой будет храниться продолжительность запроса. Окончательный код будет выглядеть так:
//+------------------------------------------------------------------+ //| HttpResponse.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "../Constants/HttpStatusCode.mqh" #include "../Header/HttpBody.mqh" #include "../Header/HttpHeader.mqh" //+------------------------------------------------------------------+ //| class : CHttpResponse | //| | //| [PROPERTY] | //| Name : CHttpResponse | //| Heritage : No heritage | //| Description : gathers elements of an http response such as body, | //| header, status code and duration | //| | //+------------------------------------------------------------------+ class CHttpResponse { private: CHttpHeader *m_header; CHttpBody *m_body; CHttpStatusCodes *m_status_code; ulong m_duration; public: CHttpResponse(void); ~CHttpResponse(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpResponse::CHttpResponse(void) { m_header = new CHttpHeader(); m_body = new CHttpBody(); m_status_code = new CHttpStatusCodes(); m_duration = 0; // Reset duration } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpResponse::~CHttpResponse(void) { delete m_header; delete m_body; delete m_status_code; } //+------------------------------------------------------------------+
Теперь перейдем к методам, которые будут добавлены в этот класс. Мы начнем с самых простых, которые просто возвращают указатели каждого из экземпляров классов, а также методов для установки и получения длительности:
- CHttpHeader *Header(void) : Возвращает указатель на заголовок.
- CHttpBody *Body(void) : Возвращает указатель на тело.
- CHttpStatusCodes *StatusCode(void) : Возвращает указатель на код состояния.
- void Duration(ulong duration) : Устанавливает продолжительность.
- ulong Duration(void) : Получает продолжительность.
Мы создадим те же вспомогательные методы для CHttpRequest для этого класса:
-
void Clear(void) : Удаляет все данные из экземпляров.
-
string FormatString(void) : Генерирует строку, содержащую все данные ответа.
Пример отформатированного ответа
HTTP-ответ: --------------- Status Code: 200 OK Duration: 120ms Headers: --------------- Content-Type: application/json Content-Length: 256 Server: Apache/2.4.41 (Ubuntu) Date: Wed, 02 Oct 2024 12:34:56 GMT Body: --------------- { "message": "Success", "data": { "id": 123, "name": "Sample Item", "status": "active" } } ---------------
Ниже приведен код с реализацией этих функций:
//+------------------------------------------------------------------+ //| HttpResponse.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpResponse | //| | //| [PROPERTY] | //| Name : CHttpResponse | //| Heritage : No heritage | //| Description : gathers elements of an http response such as body, | //| header, status code and duration | //| | //+------------------------------------------------------------------+ class CHttpResponse { public: //--- HTTP CHttpHeader *Header(void); // Get header object CHttpBody *Body(void); // Get body object CHttpStatusCodes *StatusCode(void); // Get status code object //--- Duration void Duration(ulong duration); // Set duration ulong Duration(void); // Get duration //--- Auxiliary methods void Clear(void); // Reset data string FormatString(void); // Format data }; //+------------------------------------------------------------------+ //| Get header object | //+------------------------------------------------------------------+ CHttpHeader *CHttpResponse::Header(void) { return(GetPointer(m_header)); } //+------------------------------------------------------------------+ //| Get body object | //+------------------------------------------------------------------+ CHttpBody *CHttpResponse::Body(void) { return(GetPointer(m_body)); }; //+------------------------------------------------------------------+ //| Get status code object | //+------------------------------------------------------------------+ CHttpStatusCodes *CHttpResponse::StatusCode(void) { return(GetPointer(m_status_code)); }; //+------------------------------------------------------------------+ //| Set duration | //+------------------------------------------------------------------+ void CHttpResponse::Duration(ulong duration) { m_duration = duration; } //+------------------------------------------------------------------+ //| Get duration | //+------------------------------------------------------------------+ ulong CHttpResponse::Duration(void) { return(m_duration); } //+------------------------------------------------------------------+ //| Reset data | //+------------------------------------------------------------------+ void CHttpResponse::Clear(void) { m_header.Clear(); m_body.Clear(); m_status_code.SetStatusCode(HTTP_STATUS_URL_NOT_ALLOWED); } //+------------------------------------------------------------------+ //| Format data | //+------------------------------------------------------------------+ string CHttpResponse::FormatString(void) { return( "HTTP Response:"+ "\n---------------"+ "\nStatus Code: "+m_status_code.GetStatusCodeFormat()+ "\nDuration: "+IntegerToString(m_duration)+" ms"+ "\n"+ "\n---------------"+ "\nHeaders:"+ "\n"+m_header.Serialize()+ "\n---------------"+ "\nBody:"+ "\n"+m_body.GetAsString()+ "\n---------------" ); } //+------------------------------------------------------------------+
Просто хочу напомнить вам, что здесь я привожу только изменения в классе, чтобы не сделать статью слишком длинной. Весь используемый код прикреплен в конце статьи.
На этом мы завершаем класс ответа. Это относительно простые классы и цель у них одна: сгруппировать элементы запроса или ответа. Таким образом, мы можем работать с запросом как с единым объектом, значительно упрощая использование HTTP-запросов и ответов. С этим новым классом CHttpResponse обновленная схема выглядит следующим образом:
Примеры использования
Вкратце, я приведу несколько примеров использования этих классов. Начиная с CHttpRequest, я создам HTTP-запрос с использованием этого класса.
//--- Example 1 - GET CHttpRequest request; request.Method() = HTTP_METHOD_GET; request.Url().Parse("http://example.com/api/symbols"); //--- Example 2 - POST CHttpRequest request; request.Method() = HTTP_METHOD_POST; request.Url().Parse("http://example.com/api/symbols"); request.Body().AddToString("{\"EURUSD\":1.08312}"); request.Header().Add("content-type","application/json"); //--- Example 3 - DELETE CHttpRequest request; request.Method() = HTTP_METHOD_DELETE; request.Url().Parse("http://example.com/api/symbols?symbol=EURUSD");
Большим преимуществом здесь является простота создания запроса, добавления заголовка и тела или изменения метода HTTP.
Что касается ответов, то нам нужно обратное, то есть вместо лёгкого создания объекта запроса нам надо легко прочитать объект ответа, и оба они работают аналогичным образом, что дает возможность простого создания и чтения. Я добавлю изображение, показывающее, как выглядит экран разработчика с использованием Connexus:
Обратите внимание, что мы можем получить доступ к телу ответа в различных форматах, таких как строка, json или двоичный файл. Здесь мы получаем прямой доступ к указателю класса CHttpBody, а затем ко всем его методам. Когда мы создавали класс для каждого из этих элементов ответа, я думал о том, чтобы перейти к этой части библиотеки, где мы используем каждый из классов.
Заключение
В настоящей статье мы рассмотрели важность наличия объекта CHttpRequest, который группирует все компоненты HTTP-запроса, обеспечивая ясность, возможность повторного использования и простоту обслуживания кода. Мы также увидели, как можно применить паттерн дизайна Facade для упрощения взаимодействия со сложными компонентами, скрывая внутреннюю сложность и предлагая чистый и эффективный интерфейс. В контексте Connexus применение паттерна Facade к классу ChttpRequest упрощает создание полноценных HTTP-запросов, упрощая процесс для разработчика, а также создавая класс CHttpResponse, который соответствует тому же формату, но должен облегчить доступ к данным HTTP-ответа.
В следующей статье мы подробнее рассмотрим транспортный уровень, который должен получать объект CHttpRequest и преобразовывать данные в функцию WebRequest, являющуюся последним уровнем библиотеки. Она должна иметь возможность обрабатывать данные ответа и возвращать объект типа CHttpResponse, чтобы разработчик мог затем использовать данные ответа. До встречи в новой статье!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16182






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