English 中文 Español Deutsch 日本語
preview
Тело в Connexus (Часть 4): Добавление поддержки тела HTTP-запроса

Тело в Connexus (Часть 4): Добавление поддержки тела HTTP-запроса

MetaTrader 5Примеры | 29 мая 2025, 09:30
248 0
joaopedrodev
joaopedrodev

Введение

Данная статья является продолжением серии статей, в которых мы будем создавать библиотеку под названием Connexus. В первой статье мы разобрались с основами работы функции WebRequest, разобрались с каждым из ее параметров, а также создали пример кода, который демонстрирует использование данной функции и связанные с этим трудности. В прошлой статье мы разобрались с тем, как работает запрос, что такое заголовки и как использовать заголовки для создания запроса. В конце мы разработали поддержку различных заголовков в библиотеке.

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


Что такое тело в HTTP?

В протоколе HTTP тело запроса или ответа относится к фактическому содержимому, которое отправляется или принимается. Проще говоря, тело - это место, где хранятся интересующие нас данные, которые мы хотим отправить на сервер или получить с сервера. Это основной компонент запросов типов POST , PUT и PATH, в которых необходимо отправлять такую информацию, как формы, структурированные данные в таких форматах, как JSON или XML, и даже файл. В этой серии статей основное внимание будет уделено использованию формата JSON, который чаще всего применяется для использования API, но знайте, что мы можем отправлять данные и в других форматах.

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

Тело HTTP используется для передачи информации от клиента к серверу или наоборот, в зависимости от типа запроса. Это жизненно важно при выполнении операций, связанных с созданием, обновлением или даже удалением данных. Соответственно, основная функция тела заключается в передаче "реального контента", который сервер должен обработать. Без этого HTTP com не работает! Теперь просто преобразуем его в массив символов: общение будет ограничено простыми запросами информации, без возможности передачи сложных данных или выполнения более сложных действий.

Теперь, когда мы понимаем роль тела в HTTP-коммуникации, важно знать, как корректно использовать его в запросах. В зависимости от типа данных, которые вы хотите отправить, тело может иметь различные форматы, такие как JSON, XML или двоичные данные (в таких случаях, как загрузка файлов). Давайте рассмотрим несколько практических примеров.

  1. Тело в формате JSON: Формат JSON (JavaScript Object Notation) является наиболее распространенным в современных приложениях, особенно в REST API. Он легкий, легко читаемый и идеально подходит для передачи структурированных данных, а также будет наиболее широко применяемым форматом при использовании HTTP на MQL5. Давайте рассмотрим, как JSON будет использоваться в теле запроса:

    {
      "type": "BUY",
      "symbol": "EURUSD",
      "price": 1.09223
      "volume": 0.01
      "tp": 1.09233
      "sl": 1.09213
    }

    В этом примере мы отправляем данные о транзакциях на сервер, чтобы сервер мог получать и обрабатывать данные, сохраняя их в базе данных и создавая панель мониторинга с показателями эффективности для транзакций по счету, или он может просто повторно отправлять данные о транзакциях другим учетным записям, создавая систему копирования транзакций. Для использования этого тела, необходимо указать в заголовке, что тип контента - JSON:

    Content-Type: application/json

  1. Основной текст: Другой распространенный способ отправки данных в HTTP-запросе - в обычном текстовом формате. Этот формат выгоден своей простотой. Вам просто нужно написать то, что вы хотите отправить, не соблюдая многих правил или условностей, при условии, что сервер поддерживает отправляемую информацию. Он не рекомендуется для отправки данных, так как сложно организовать большое количество данных. Для этого сценария наиболее рекомендуемым форматом является JSON. Давайте рассмотрим пример обычного текста:

    Это образец обычного текста

    Здесь поля формы объединены и разделены символом &, и каждому значению присвоен определенный ключ. Для использования этого формата заголовок должен быть установлен следующим образом:

    Content-Type: application/text-plain

    Это один из старейших форматов, но он по-прежнему широко используется в различных приложениях. Наша библиотека Connexus будет поддерживать этот тип контента, позволяя разработчикам выбирать подход, который наилучшим образом соответствует их вариантам использования.


Добавление тела к HTTP-запросу

Рассмотрим практический пример, в котором отправим JSON-файл в теле запроса и проверим, корректно ли его получил сервер. Для выполнения этой проверки продолжим использовать httpbin, о котором уже упоминалось в предыдущих статьях. С самого начала я создам еще один файл с именем TestBody.mq5 в папке Experts/Connexus/Test/TestBody.mq5 и добавлю простой запрос post, который использовался в предыдущей статье. Все использованные в этой статье файлы прилагаются в конце.

//+------------------------------------------------------------------+
//|                                                     TestBody.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Connexus/Data/Json.mqh>
#include <Connexus/URL/URL.mqh>
#include <Connexus/Header/HttpHeader.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   char body_send[];
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","application/json");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Тело запроса должно присутствовать в переменной body_send, которая представляет собой массив типа char. Возможно, вам интересно, почему бы не использовать тип string вместо char[], string был бы идеальным для отправки JSON или текста? По нескольким причинам, связанным с гибкостью, эффективностью и совместимостью. Вот несколько подробных причин:

  • Гибкость типов данных: Тело HTTP-запроса может содержать различные типы данных, такие как текст, JSON, двоичные (файлы, изображения) или другие форматы. Использование массива символов позволяет функции принимать данные любого типа, независимо от того, представлены ли они в текстовом или двоичном виде. Если тело содержит файл (изображение, аудио и т.д.), необходимо манипулировать им как массивом байтов, который может быть обработан непосредственно в массиве символов. Строка была бы полезна только для чисто текстовых данных, что ограничивает использование функции сценариями, в которых содержимое является двоичным.
  • Эффективность: массив символов является более эффективным с точки зрения манипулирования данными. Поскольку они не требуют дополнительных затрат на динамическое управление строками (таких как выделение и перераспределение памяти), они позволяют сетевому коду работать ближе к аппаратному обеспечению, что важно для приложений, требующих высокой производительности, таких как передача больших файлов или запросы с низкой задержкой. При отправке запроса с большим файлом изображения использование массива символов позволяет избежать необходимости преобразования двоичного содержимого в строку, экономя время работы процессора.
  • Совместимость с протоколом HTTP: Протокол HTTP работает непосредственно с байтами при передаче данных по сетям. Массив символов (который представляет собой последовательность байтов) лучше отражает это низкоуровневое поведение протокола. Таким образом, при использовании массивов символов функция HTTP-запроса будет приведена в соответствие со способом обработки и передачи данных на сетевом уровне.

Использование массива символов в теле HTTP-запроса обеспечивает превосходную гибкость, эффективность и совместимость, особенно в сценариях, связанных с двоичными данными или большими объемами данных. Это позволяет функции напрямую обрабатывать данные в их самой простой форме (байтах), избегая расходования ресурсов и ограничений, связанных со строками, которые больше подходят для текстовых данных.

Теперь, когда мы это поняли, добавим тело к этому запросу. Для этого мы используем функцию StringToCharArray(), давайте рассмотрим, что говорится в документации об этой функции:

Параметр
Тип
Описание
text_string
string
Строка для копирования.
array[]
char[]
Массив типа uchar.
start
int
Позиция, с которой начинается копирование. Значение по умолчанию равно 0.
count
int
Количество элементов массива для копирования. Определяет длину результирующей строки. Значение по умолчанию минус 1, что означает копирование до конца массива или до терминала 0. Терминал 0 также будет скопирован в массив-приёмник, в этом случае размер динамического массива может быть увеличен при необходимости до размера строки. Если размер динамического массива превышает длину строки, размер массива не будет уменьшен.
codepage
uint Значение кодовой страницы. При преобразовании строковых переменных в массивы типа char и наоборот, в MQL5 используется кодировка, которая по умолчанию соответствует текущему ANSI операционной системы Windows (CP_ACP). Если надо указать другой тип кодировки, его можно задать в этом параметре.

В таблице ниже приведен список внутренних постоянных некоторых из наиболее популярных кодовых страниц. Неуказанные кодовые страницы можно указать с помощью соответствующей кодовой страницы.

Константа
Значение Описание
CP_ACP
0
Текущая кодовая страница Windows ANSI.
CP_OEMCP
1 Текущая кодовая страница системы OEM.
CP_MACCP
2 Текущая кодовая страница системы Macintosh. Это значение в основном использовалось в ранее созданных программных кодах, а сейчас не используется, поскольку современные компьютеры Macintosh используют для кодирования Unicode.
CP_THREAD_ACP
3 Кодовая страница Windows ANSI для текущего потока.
CP_SYMBOL
42 Кодовая страница символа
CP_UTF7
65000 Кодовая страница UTF-7.
CP_UTF8
65001 Кодовая страница UTF-8.

Для большинства API мы будем использовать UTF8, который является стандартным типом кодировки для электронной почты, веб-страниц и т.д. Итак, добавим тело в формате json в соответствии с кодировкой UTF8:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Data to be sent
   string method = "POST";
   CJson body;
   body["type"] = "BUY";
   body["symbol"] = "EURUSD";
   body["price"] = 1.09223;
   body["volume"] = 0.01;
   body["tp"] = 1.09233;
   body["sl"] = 1.09213;
   //--- {"price": 1.09223,"sl": 1.09213,"symbol": "EURUSD","tp": 1.09233,"type": "BUY","volume": 0.01}
   
   //--- Char that will be sent
   char body_send[];
   
   //--- Convert string to char (UTF8)
   StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8);
   
   //--- Show char array
   ArrayPrint(body_send);
         
   return(INIT_SUCCEEDED);
  }

При запуске этого кода, он будет отображен на панели инструментов:

toolbox | experts

Обратите внимание, что в последней позиции массива у нас есть значение “0”, что может стать проблемой для сервера при чтении тела запроса. Чтобы избежать этой проблемы, мы удалим последнюю позицию массива с помощью функций ArrayRemove() и ArraySize().

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Data to be sent
   string method = "POST";
   CJson body;
   body["type"] = "BUY";
   body["symbol"] = "EURUSD";
   body["price"] = 1.09223;
   body["volume"] = 0.01;
   body["tp"] = 1.09233;
   body["sl"] = 1.09213;
   //--- {"price": 1.09223,"sl": 1.09213,"symbol": "EURUSD","tp": 1.09233,"type": "BUY","volume": 0.01}
   
   //--- Char that will be sent
   char body_send[];
   
   //--- Convert string to char (UTF8)
   StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8);
   ArrayRemove(body_send,ArraySize(body_send)-1);
   
   //--- Show char array
   ArrayPrint(body_send);
         
   return(INIT_SUCCEEDED);
  }

При повторном запуске это будет отображено на панели инструментов:

toolbox | experts

Теперь, когда мы разобрались с этой маленькой настройкой, давайте добавим это тело в http-запрос:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   CJson body;
   body["type"] = "BUY";
   body["symbol"] = "EURUSD";
   body["price"] = 1.09223;
   body["volume"] = 0.01;
   body["tp"] = 1.09233;
   body["sl"] = 1.09213;
   char body_send[];
   StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8);
   ArrayRemove(body_send,ArraySize(body_send)-1);
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","application/json");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

При запуске этого кода мы получим следующий ответ от httpbin:

Respose: {
  "args": {}, 
  "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":1.09223000,\"volume\":0.01000000,\"tp\":1.09233000,\"sl\":1.09213000}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Accept-Language": "pt,en;q=0.5", 
    "Content-Length": "103", 
    "Content-Type": "text/plain", 
    "Host": "httpbin.org", 
    "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", 
    "X-Amzn-Trace-Id": "Root=1-67081b9c-3def4b1527d04edc1511cc6b"
  }, 
  "json": {
    "price": 1.09223, 
    "sl": 1.09213, 
    "symbol": "EURUSD", 
    "tp": 1.09233, 
    "type": "BUY", 
    "volume": 0.01
  }, 
  "origin": "189.74.63.39", 
  "url": "https://httpbin.org/post"
}

Обратите внимание на два интересных момента, во-первых, поле “data” содержит JSON, который мы отправили в теле в строковом формате, что означает, что сервер смог получить и корректно интерпретировать отправленные данные. Еще один момент, на который следует обратить внимание, это то, что поле “json” содержит отправленный нами JSON, что еще раз показывает, что сервер корректно получил данные. Работает замечательно!


Создание класса CHttpBody

Теперь, когда мы понимаем, как работает тело, для чего оно предназначено и как его использовать, давайте создадим класс в библиотеке Connexus для работы с телом запроса. Имя этого класса будет CHttpBody, и у него будут методы для работы с телом, позволяющие добавлять, обновлять или удалять данные. Также можно будет определить используемую кодировку (по умолчанию будет использоваться UTF 8).

Давайте создадим новый файл под названием HttpBody.mqh в папке Include/Connexus/Header/HttpBody.mqh. При создании файл изначально будет выглядеть примерно так:

//+------------------------------------------------------------------+
//|                                                     HttpBody.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| class : CHttpBody                                                |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpBody                                          |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the body of |
//|               a request.                                         |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpBody
  {
public:
                     CHttpBody(void);
                    ~CHttpBody(void);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpBody::CHttpBody(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpBody::~CHttpBody(void)
  {
  }
//+------------------------------------------------------------------+

Давайте определим некоторые частные свойства класса, а именно:

  • m_body : Будет хранить тело запроса в виде массива символов.
  • m_codepage : Используется для хранения определенной кодировки
//+------------------------------------------------------------------+
//| Include the file CJson class                                     |
//+------------------------------------------------------------------+
#include "../Data/Json.mqh"
//+------------------------------------------------------------------+
//| class : CHttpBody                                                |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpBody                                          |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the body of |
//|               a request.                                         |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpBody
  {
private:
   
   char              m_body[];                           // Will store the request body as a char array
   uint              m_codepage;                         // Used to store the defined encoding
  };;
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpBody::CHttpBody(void)
  {
   m_codepage = CP_UTF8;
  }
//+------------------------------------------------------------------+

Теперь определим некоторые общедоступные методы для обработки тела запроса:

  • Добавление данных в тело
    • AddString(string data) : Добавляет текстовую строку в тело запроса.
    • AddJson(CJson data) : Добавляет данные в формате JSON в тело. Это может включать в себя преобразование объекта JSON в отформатированную строку.
    • AddBinary(char &data[]) : Позволяет добавлять двоичные данные (например, файлы) непосредственно в текст запроса.
  • Удаление данных из тела
    • Clear(void) : Удаляет все содержимое из текста запроса, позволяя начать с нуля.
  • Получение содержания тела
    • GetAsString(void) : Возвращает тело запроса в виде строки.
    • GetAsJson(void) : Преобразует тело запроса в объект JSON, что удобно, когда тело содержит структурированные данные. - GetAsChar(char &body[]) : Возвращает тело в виде массива байтов, что удобно для работы с двоичными данными.
  • Проверка размера тела
    • GetSize(void) : Возвращает размер тела запроса, обычно в байтах.
  • Кодирование
    • GetCodePage(void) : Возвращает определенную кодовую страницу
    • SetCodePage(uint codepage) : Настраивает используемую кодовую страницу

Добавим эти методы к классам, в итоге это будет выглядеть так:

//+------------------------------------------------------------------+
//| class : CHttpBody                                                |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpBody                                          |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the body of |
//|               a request.                                         |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpBody
  {
private:
   
   char              m_body[];                           // Will store the request body as a char array
   uint              m_codepage;                         // Used to store the defined encoding
   
public:
                     CHttpBody(void);
                    ~CHttpBody(void);

   //--- Add data to the body
   void              AddString(string data);             // Adds a text string to the request body
   void              AddJson(CJson &data);               // Adds data in JSON format to the body
   void              AddBinary(char &data[]);            // Allows you to add binary data
   
   //--- Clear the body
   void              Clear(void);                        // Remove all body content
   
   //--- Gets the body content
   string            GetAsString(void);                  // Returns the request body as a string
   CJson             GetAsJson(void);                    // Converts the request body into a JSON object, useful when the body contains structured data
   void              GetAsBinary(char &body[]);          // Returns the body as an array of bytes, useful for working with binary data
   
   //--- Size in bytes
   int               GetSize(void);                      // Returns the size of the request body, usually in bytes
   
   //--- Codepage
   uint              GetCodePage(void);                  // Returns the defined codepage
   void              SetCodePage(uint codepage);         // Defines the codepage to be used
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CHttpBody::CHttpBody(void)
  {
   m_codepage = CP_UTF8;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CHttpBody::~CHttpBody(void)
  {
  }
//+------------------------------------------------------------------+
//| Adds a text string to the request body                           |
//+------------------------------------------------------------------+
void CHttpBody::AddString(string data)
  {
   StringToCharArray(data,m_body,this.GetSize()-1,WHOLE_ARRAY,m_codepage);
   ArrayRemove(m_body,this.GetSize()-1);
  }
//+------------------------------------------------------------------+
//| Adds data in JSON format to the body                             |
//+------------------------------------------------------------------+
void CHttpBody::AddJson(CJson &data)
  {
   this.AddString(data.Serialize());
  }
//+------------------------------------------------------------------+
//| Allows you to add binary data                                    |
//+------------------------------------------------------------------+
void CHttpBody::AddBinary(char &data[])
  {
   ArrayCopy(m_body,data);
  }
//+------------------------------------------------------------------+
//| Remove all body content                                          |
//+------------------------------------------------------------------+
void CHttpBody::Clear(void)
  {
   ArrayFree(m_body);
  }
//+------------------------------------------------------------------+
//| Returns the request body as a string                             |
//+------------------------------------------------------------------+
string CHttpBody::GetAsString(void)
  {
   return(CharArrayToString(m_body,0,WHOLE_ARRAY,m_codepage));
  }
//+------------------------------------------------------------------+
//| Converts the request body into a JSON object, useful when the    |
//| body contains structured data                                    |
//+------------------------------------------------------------------+
CJson CHttpBody::GetAsJson(void)
  {
   CJson json;
   json.Deserialize(this.GetAsString());
   return(json);
  }
//+------------------------------------------------------------------+
//| Returns the body as an array of bytes, useful for working with   |
//| binary data                                                      |
//+------------------------------------------------------------------+
void CHttpBody::GetAsBinary(char &body[])
  {
   ArrayCopy(body,m_body);
  }
//+------------------------------------------------------------------+
//| Returns the size of the request body, usually in bytes           |
//+------------------------------------------------------------------+
int CHttpBody::GetSize(void)
  {
   return(ArraySize(m_body));
  }
//+------------------------------------------------------------------+
//| Returns the defined codepage                                     |
//+------------------------------------------------------------------+
uint CHttpBody::GetCodePage(void)
  {
   return(m_codepage);
  }
//+------------------------------------------------------------------+
//| Defines the codepage to be used                                  |
//+------------------------------------------------------------------+
void CHttpBody::SetCodePage(uint codepage)
  {
   m_codepage = codepage;
  }
//+------------------------------------------------------------------+

Эти методы просты и понятны — самый большой из них имеет длину всего в три строки. Однако не позволяйте их простоте ввести вас в заблуждение. Они чрезвычайно полезны и окажут значительное влияние на сокращение общего количества строк кода в вашей библиотеке. Они не только сделают ваш код более компактным, но и значительно упростят использование и обслуживание вашей библиотеки.


Тесты

Перейдем к тестам и посмотрим, как ведет себя класс. Я буду использовать тот же файл, что и в начале статьи, TestBody.mq5 .

{
  "type": "BUY",
  "symbol": "EURUSD",
  "price": 1.09223
  "volume": 0.01
  "tp": 1.09233
  "sl": 1.09213
}

В этом тесте мы добавим этот JSON-файл в тело POST-запроса. Мы создадим объект json с данными:

CJson body_json;
body_json["type"] = "BUY";
body_json["symbol"] = "EURUSD";
body_json["price"] = 1.09223;
body_json["volume"] = 0.01;
body_json["tp"] = 1.09233;
body_json["sl"] = 1.09213;

Создадим экземпляр класса CHttpBody и добавим в него этот JSON-файл:

CHttpBody body;
body.AddJson(body_json);

Готово! Теперь просто преобразуем его в массив символов:

//--- Body in char array
char body_send[];
body.GetAsBinary(body_send);

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

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   CJson body_json;
   body_json["type"] = "BUY";
   body_json["symbol"] = "EURUSD";
   body_json["price"] = 1.09223;
   body_json["volume"] = 0.01;
   body_json["tp"] = 1.09233;
   body_json["sl"] = 1.09213;
   CHttpBody body;
   body.AddJson(body_json);
   
   //--- Body in char array
   char body_send[];
   body.GetAsBinary(body_send);
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","application/json");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
Во время работы мы получим такой результат:
Respose: {
  "args": {}, 
  "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":1.09223000,\"volume\":0.01000000,\"tp\":1.09233000,\"sl\":1.09213000}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Accept-Language": "pt,en;q=0.5", 
    "Content-Length": "103", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", 
    "X-Amzn-Trace-Id": "Root=1-670902d1-5a796b1e1fe2053f18a07654"
  }, 
  "json": {
    "price": 1.09223, 
    "sl": 1.09213, 
    "symbol": "EURUSD", 
    "tp": 1.09233, 
    "type": "BUY", 
    "volume": 0.01
  }, 
  "origin": "189.74.63.39", 
  "url": "https://httpbin.org/post"
}

Обратите внимание еще раз, что поля “data” и “json” содержат внутри себя объект, что означает, что сервер корректно получил данные, которые мы отправили в теле. Если вы хотите отправить текстовое сообщение с обычным текстом, без форматирования, просто вставьте его в класс CHttpBody в виде строки и измените заголовок на text/plain, как описано в предыдущей статье:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- URL
   CURL url;
   url.Parse("https://httpbin.org");
   url.Path("post");
   
   //--- Data to be sent
   string method = "POST";
   CHttpBody body;
   body.AddString("My simple text");
   
   //--- Body in char array
   char body_send[];
   body.GetAsBinary(body_send);
   
   //--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)");
   headers_send.Add("Content-Type","text/plain");
   
   //--- Data that will be received
   char body_receive[];
   string headers_receive;
   
   //--- Send request
   int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive);
   
   //--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+


Заключение

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

Мы также представили создание класса CHttpBody в библиотеке Connexus, который будет отвечать за облегчение работы с телом запроса. Этот класс позволяет легко манипулировать данными, которые будут отправлены, не беспокоясь о низкоуровневом форматировании (в байтах).

В следующей статье серии мы еще глубже разберемся в работе протокола HTTP, исследуя некоторые методы, такие как GET, POST, PUT, DELETE и другие. Мы также обсудим коды состояния HTTP, такие как 200 (Ok), возможно, самый известный в Интернете, 404 (Не найден) и другие, такие как 500 (Внутренняя ошибка сервера), и то, что они означают для взаимодействия клиент-сервер. Следите за обновлениями!

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

Прикрепленные файлы |
Индикатор прогнозирования ARIMA на MQL5 Индикатор прогнозирования ARIMA на MQL5
В данной статье мы создаем индикатор прогнозирования ARIMA на MQL5. Рассматривается, как модель ARIMA формирует прогнозы, её применимость к рынку Форекс и фондовому рынку в целом. Также объясняется, что такое авторегрессия AR, каким образом авторегрессионные модели используются для прогнозирования, и как работает механизм авторегрессии.
Создание торговой панели администратора на MQL5 (Часть V): Двухфакторная аутентификация (2FA) Создание торговой панели администратора на MQL5 (Часть V): Двухфакторная аутентификация (2FA)
В статье рассмотрено повышение безопасности панели торгового администратора, которая в настоящее время находится в разработке. Мы рассмотрим, как внедрить MQL5 в новую стратегию безопасности, интегрировав API Telegram для двухфакторной аутентификации (2FA). Статья предоставит ценную информацию о применении MQL5 для усиления мер безопасности. Кроме того, мы рассмотрим функцию MathRand, сосредоточившись на ее функциональности и на том, как ее можно эффективно использовать в нашей системе безопасности.
Нейросети в трейдинге: Эффективное извлечение признаков для точной классификации (Построение объектов) Нейросети в трейдинге: Эффективное извлечение признаков для точной классификации (Построение объектов)
Mantis — универсальный инструмент для глубокого анализа временных рядов, гибко масштабируемый под любые финансовые сценарии. Узнайте, как сочетание патчинга, локальных свёрток и кросс-внимания позволяет получить высокоточную интерпретацию рыночных паттернов.
Нейросети в трейдинге: Эффективное извлечение признаков для точной классификации (Mantis) Нейросети в трейдинге: Эффективное извлечение признаков для точной классификации (Mantis)
Познакомьтесь с Mantis — лёгкой фундаментальной моделью для классификации временных рядов на базе Transformer с контрастным предварительным обучением и гибридным вниманием, обеспечивающими рекордную точность и масштабируемость.