English Русский 中文 Deutsch 日本語
preview
Cuerpo en Connexus (Parte 4): Añadiendo compatibilidad con cuerpos HTTP

Cuerpo en Connexus (Parte 4): Añadiendo compatibilidad con cuerpos HTTP

MetaTrader 5Ejemplos |
163 1
joaopedrodev
joaopedrodev

Introducción

Este artículo es una continuación de una serie de artículos donde construiremos una biblioteca llamada Connexus. En el primer artículo, comprendimos el funcionamiento básico de la función WebRequest, entendimos cada uno de sus parámetros y también creamos un código de ejemplo que muestra el uso de esta función y sus dificultades. En el último artículo comprendimos cómo funciona una solicitud, qué son los encabezados y cómo utilizarlos para realizar una solicitud, y al final desarrollamos soporte para diferentes encabezados en la biblioteca.

En el desarrollo de API, la comunicación entre el cliente y el servidor implica el envío de información esencial a través de una solicitud HTTP. Y, si los encabezados son como el sobre de esta comunicación, el cuerpo es la carta en sí, que contiene los datos reales que desea transmitir. En el artículo de hoy, exploraremos el rol del cuerpo en una solicitud HTTP, su importancia y cómo configurarlo correctamente con Connexus. ¡Comencemos!


¿Qué es un cuerpo en HTTP?

En el protocolo HTTP, el cuerpo de una solicitud o respuesta se refiere al contenido real que se envía o recibe. En términos simples, el cuerpo es donde se almacenan los datos que nos interesan, que queremos enviar al servidor, o recibir del servidor. Es el componente principal de las peticiones de tipo POST, PUT y PATH, en las que es necesario enviar información como formularios, datos estructurados en formatos como JSON o XML, e incluso un archivo. En esta serie de artículos nos centraremos principalmente en el uso del formato JSON, que es el más utilizado para consumir APIs, pero sepamos que podemos enviar en otros formatos.

En una petición de tipo GET no suele haber cuerpo, ya que este tipo de peticiones se utilizan para consultar datos, es decir para recibir información y no para enviarla. Normalmente el servidor responde a este tipo de solicitud con un cuerpo que contiene los resultados solicitados. Sin embargo, en una petición POST, el cuerpo es esencial, ya que es a través de él que se envían los datos al servidor para ser procesados. El servidor puede o no responder a este tipo de solicitud con otro cuerpo.

El cuerpo HTTP se utiliza para transmitir información del cliente al servidor, o viceversa, dependiendo del tipo de solicitud. Es vital en operaciones que implican crear, actualizar o incluso eliminar datos. La función principal del cuerpo es, por tanto, transportar el "contenido real" que el servidor necesita procesar. Sin él, la comunicación HTTP queda incompleta. Ahora sólo hay que convertirlo a un array de caracteres: la comunicación quedaría limitada a meras solicitudes de información, sin posibilidad de transmitir datos complejos ni realizar acciones más sofisticadas.

Ahora que entendemos el papel del cuerpo en la comunicación HTTP, es importante saber cómo usarlo correctamente en las solicitudes. Dependiendo del tipo de datos que desee enviar, el cuerpo puede tener diferentes formatos, como JSON, XML o datos binarios (en casos como la carga de archivos). Veamos algunos ejemplos prácticos.

  1. Cuerpo JSON: El formato JSON (JavaScript Object Notation) es el más común en las aplicaciones modernas, especialmente en las API REST. Es liviano, fácil de leer e ideal para transportar datos estructurados, y será el formato más utilizado cuando se utilice HTTP en MQL5. Veamos cómo se usaría JSON en el cuerpo de una solicitud:

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

    En este ejemplo, estamos enviando datos de transacciones al servidor, para que el servidor pueda recibir y procesar los datos, guardándolos en una base de datos y generando un tablero con métricas de desempeño de las transacciones de la cuenta, o simplemente puede reenviar los datos de transacciones a otras cuentas, creando un sistema de copia de transacciones. Para utilizar este cuerpo, debe especificar en el encabezado que el tipo de contenido es JSON:

    Content-Type: application/json

  1. Texto del cuerpo: Otra forma habitual de enviar datos en una solicitud HTTP es en formato de texto sin formato. Este formato es ventajoso debido a su simplicidad. Solo necesitas escribir lo que quieres enviar sin seguir muchas reglas o convenciones, siempre y cuando el servidor admita lo que se envía. No se recomienda para enviar datos, ya que es difícil organizar muchos datos. Para este escenario, el formato más recomendado es JSON. Veamos un ejemplo de texto plano:

    Este es un ejemplo de texto sin formato.

    Aquí, los campos del formulario se concatenan y se separan mediante el símbolo &, y a cada valor se le asigna una clave específica. Para utilizar este formato, el encabezado debe configurarse como:

    Content-Type: application/text-plain

    Este es uno de los formatos más antiguos, pero todavía se utiliza ampliamente en diversas aplicaciones. Nuestra biblioteca Connexus admitirá este tipo de contenido, lo que permitirá a los desarrolladores elegir el enfoque que mejor se adapte a sus casos de uso.


Agregar un cuerpo a una solicitud HTTP

Tomemos un ejemplo práctico donde enviaremos un JSON en el cuerpo de una solicitud y verificaremos si el servidor lo recibió correctamente. Para realizar esta comprobación, seguiremos utilizando httpbin, que ya se ha mencionado en artículos anteriores. Desde el principio, crearé otro archivo llamado TestBody.mq5 en la carpeta Experts/Connexus/Test/TestBody.mq5 y añadiré una simple solicitud POST que se utilizó en el último artículo. Todos los archivos utilizados en este artículo se adjuntan al final.

//+------------------------------------------------------------------+
//|                                                     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);
  }
//+------------------------------------------------------------------+

El cuerpo de la solicitud debe estar presente en la variable body_send, que es una matriz de tipo char. Quizás te preguntes: ¿por qué no utilizar el tipo string en lugar de char[], ya que string sería ideal para enviar JSON o texto? Por varias razones relacionadas con la flexibilidad, el rendimiento y la compatibilidad. A continuación se detallan algunas razones:

  • Flexibilidad del tipo de datos: El cuerpo de una solicitud HTTP puede contener varios tipos de datos, como texto, JSON, binario (archivos, imágenes) u otros formatos. El uso de una matriz de caracteres permite que la función acepte cualquier tipo de datos, independientemente de si se representan como texto o binario. Si el cuerpo contiene un archivo (imagen, audio, etc.), es necesario manipularlo como una matriz de bytes, que se puede manejar directamente en una matriz de caracteres. Una cadena solo sería útil para datos puramente textuales, lo que limita el uso de la función a escenarios donde el contenido es binario.
  • Rendimiento: las matrices de caracteres son más eficientes en términos de manipulación de datos de bajo nivel. Dado que no implican la sobrecarga que supone la gestión dinámica de cadenas (como la asignación y reasignación de memoria), permiten que el código de red funcione más cerca del hardware, lo cual es esencial para aplicaciones que requieren un alto rendimiento, como la transmisión de archivos de gran tamaño o las solicitudes de baja latencia. Al enviar una solicitud con un archivo de imagen grande, el uso de una matriz de caracteres evita la necesidad de convertir el contenido binario en una cadena, lo que ahorra ciclos de CPU.
  • Compatibilidad con el protocolo HTTP: El protocolo HTTP trabaja directamente con bytes cuando transmite datos a través de redes. Una matriz de caracteres (que es una secuencia de bytes) refleja mejor este comportamiento de bajo nivel del protocolo. Por lo tanto, al utilizar matrices de caracteres, la función de solicitud HTTP se alineará con la forma en que se manejan y transmiten los datos a nivel de red.

El uso de una matriz de caracteres para el cuerpo de una solicitud HTTP ofrece flexibilidad, rendimiento y compatibilidad superiores, especialmente en escenarios que involucran datos binarios o grandes volúmenes de datos. Permite que la función trate directamente con los datos en su forma más básica (bytes), evitando la sobrecarga y las limitaciones de trabajar con cadenas, que son más adecuadas para datos textuales.

Ahora que entendemos esto, agreguemos un cuerpo a esta solicitud. Para ello, utilizaremos la función StringToCharArray(). Veamos qué dice la documentación sobre esta función:

Parámetro
Tipo
Descripción
text_string
string
Cadena a copiar.
array[]
char[]
Matriz de tipo uchar.
start
int
Posición desde la que se inicia la copia. Predeterminado: 0.
count
int
Número de elementos de la matriz a copiar. Define la longitud de una cadena resultante. El valor predeterminado es -1, lo que significa copiar hasta el final de la matriz o hasta la terminal 0. El terminal 0 también se copiará a la matriz de destinatarios, en este caso el tamaño de una matriz dinámica se puede aumentar si es necesario al tamaño de la cadena. Si el tamaño de la matriz dinámica excede la longitud de la cadena, el tamaño de la matriz no se reducirá.
codepage
uint El valor de la página de códigos. Al convertir variables de cadena a matrices de tipo char y viceversa, en MQL5 se utiliza la codificación que por defecto corresponde al ANSI actual del sistema operativo Windows (CP_ACP). Si desea especificar un tipo de codificación diferente, puede configurarlo en este parámetro.

La siguiente tabla muestra las constantes internas de algunas de las páginas de códigos más populares. Las páginas de códigos no especificadas se pueden especificar utilizando la página de códigos correspondiente.

Constante
Valor Descripción
CP_ACP
0
La página de códigos ANSI de Windows actual.
CP_OEMCP
1 La página de códigos OEM del sistema actual.
CP_MACCP
2 La página de códigos del sistema Macintosh actual. Este valor se utiliza principalmente en códigos de programas creados anteriormente y no tiene utilidad ahora, ya que las computadoras Macintosh modernas utilizan Unicode para la codificación.
CP_THREAD_ACP
3 La página de códigos ANSI de Windows para el hilo actual.
CP_SYMBOL
42 Página de códigos de símbolos
CP_UTF7
65000 Página de códigos UTF-7.
CP_UTF8
65001 Página de códigos UTF-8.

Para la mayoría de las API, utilizaremos UTF-8, que es un tipo de codificación estándar para correo electrónico, páginas web y otros. Ahora vamos a agregar un cuerpo en formato JSON siguiendo la codificación UTF-8:

//+------------------------------------------------------------------+
//| 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);
  }

Cuando ejecute este código, esto se mostrará en la caja de herramientas:

Caja de herramientas | Expertos

Tenga en cuenta que en la última posición de la matriz tenemos un valor de «0», lo que puede suponer un problema para el servidor al leer el cuerpo de la solicitud. Para evitar esto, eliminaremos la última posición de la matriz utilizando las funciones ArrayRemove() y 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);
  }

Cuando lo vuelvas a ejecutar, esto se mostrará en la Caja de herramientas:

Caja de herramientas | Expertos

Ahora que ya hemos solucionado este pequeño ajuste, vamos a añadir este cuerpo a una solicitud 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);
  }
//+------------------------------------------------------------------+

Al ejecutar este código, obtendremos esta respuesta de 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"
}

Observe dos cosas interesantes, la primera es que el campo “data” contiene el JSON que enviamos en el cuerpo en formato string, lo que significa que el servidor pudo recibir e interpretar correctamente los datos enviados. Otra cosa a destacar es que el campo “json” contiene el JSON que enviamos, mostrando una vez más que el servidor recibió correctamente los datos. ¡Funcionando perfectamente!


Creando la clase CHttpBody

Ahora que entendemos cómo funciona el cuerpo, para qué sirve y cómo usarlo, creemos una clase en la biblioteca Connexus para trabajar con el cuerpo de la solicitud. El nombre de esta clase será CHttpBody, y tendrá métodos para trabajar con el cuerpo, pudiendo agregar, actualizar o eliminar datos. También será posible definir la codificación utilizada (por defecto será UTF-8).

Creemos un nuevo archivo llamado HttpBody.mqh en la carpeta Include/Connexus/Header/HttpBody,mqh. Al crear el archivo inicialmente se verá similar a esto:

//+------------------------------------------------------------------+
//|                                                     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)
  {
  }
//+------------------------------------------------------------------+

Definamos algunas propiedades privadas de la clase, son:

  • m_body : Almacenará el cuerpo de la solicitud como una matriz de caracteres.
  • m_codepage : Se utiliza para almacenar la codificación definida.
//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Ahora definamos algunos métodos públicos para gestionar el cuerpo de la solicitud:

  • Añadir datos al cuerpo
    • AddString(string data) : Añade una cadena de texto al cuerpo de la solicitud.
    • AddJson(CJson data) : Añade datos con formato JSON al cuerpo. Esto puede implicar convertir un objeto JSON en una cadena formateada.
    • AddBinary(char &data[]) : Le permite añadir datos binarios (como archivos) directamente al cuerpo de la solicitud.
  • Eliminar datos del cuerpo
    • Clear(void) : Elimina todo el contenido del cuerpo de la solicitud, lo que te permite empezar desde cero.
  • Obtener el contenido del cuerpo
    • GetAsString(void) : Devuelve el cuerpo de la solicitud como una cadena.
    • GetAsJson(void) : Convierte el cuerpo de la solicitud en un objeto JSON, lo cual resulta útil cuando el cuerpo contiene datos estructurados. - GetAsChar(char &body[]) : Devuelve el cuerpo como una matriz de bytes, útil para trabajar con datos binarios.
  • Comprobación del tamaño del cuerpol
    • GetSize(void) : Devuelve el tamaño del cuerpo de la solicitud, normalmente en bytes.
  • Codificación
    • GetCodePage(void) : Devuelve la página de códigos definida.
    • SetCodePage(uint codepage) : Establece la página de códigos que se utilizará.

Añadamos estos métodos a las clases, al final quedará así:

//+------------------------------------------------------------------+
//| 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;
  }
//+------------------------------------------------------------------+

Estos métodos son sencillos y directos: el más extenso de ellos solo tiene tres líneas. Sin embargo, no dejes que su simplicidad te engañe. Son extremadamente útiles y tendrán un impacto significativo en la reducción del número total de líneas de código en su biblioteca. No sólo harán que su código sea más ágil, sino que también harán que su biblioteca sea mucho más fácil de usar y mantener.


Pruebas

Pasemos a las pruebas y veamos cómo se comporta la clase. Usaré el mismo archivo del principio del artículo, TestBody.mq5.

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

En esta prueba, agregaremos este JSON al cuerpo de una solicitud POST. Crearemos el objeto json con los datos:

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;

Creemos una instancia de la clase CHttpBody y agreguemos este JSON dentro de ella:

CHttpBody body;
body.AddJson(body_json);

¡Hecho! Ahora simplemente conviértalo en una matriz de caracteres:

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

Así de simple, agregamos el JSON a la solicitud sin ninguna complicación. Este último paso de convertirlo a una matriz de caracteres no será necesario al final de la biblioteca, como todavía estamos en desarrollo, todavía hacemos todo "a mano". Al final el código se verá así:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+
Al ejecutarlo tendremos este resultado:
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"
}

Observe una vez más que los campos «data» y «json» contienen un objeto en su interior, lo que significa que el servidor ha recibido correctamente los datos que enviamos en el cuerpo. Si desea enviar un cuerpo con texto sin formato, simplemente insértelo en la clase CHttpBody como una cadena y cambie el encabezado a text/plain, tal y como vimos en el último artículo:

//+------------------------------------------------------------------+
//| 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);
  }
//+------------------------------------------------------------------+


Conclusión

En este artículo, hemos explorado el concepto de cuerpo en las solicitudes HTTP, mostrando su papel fundamental en la transmisión de datos entre el cliente y el servidor. Entendemos que el cuerpo es donde colocamos los datos que queremos enviar, y puede tener diferentes formatos, como JSON, XML e incluso archivo, pero hemos explorado más el uso de JSON, que es el más utilizado en el contexto de las API, que es nuestro enfoque por ahora. Además, analizamos los encabezados necesarios para cada tipo de cuerpo, asegurándonos de que el servidor interprete correctamente la solicitud.

También hemos introducido la creación de la clase CHttpBody en la biblioteca Connexus, que se encargará de facilitar el trabajo con el cuerpo de la solicitud. Esta clase permite manipular fácilmente los datos que se enviarán, sin preocuparse por el formato de bajo nivel (bytes).

En el próximo artículo de la serie, profundizaremos aún más en el funcionamiento del protocolo HTTP, explorando algunos métodos, como GET, POST, PUT, DELETE y otros. También hablaremos de los códigos de estado HTTP, como el 200 (Ok), quizás el más famoso en la web, el 404 (No encontrado) y otros como el 500 (Error interno del servidor), y lo que significan para la comunicación cliente-servidor. ¡Estén atentos!

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16098

yucong tang
yucong tang | 4 jun 2025 en 22:37
¿Cómo enviar contenidos chinos? El contenido chino es desordenado.
Cómo crear un panel interactivo MQL5 utilizando la clase Controls (Parte 1): Configuración del panel Cómo crear un panel interactivo MQL5 utilizando la clase Controls (Parte 1): Configuración del panel
En este artículo, creamos un panel de control interactivo para operaciones bursátiles utilizando la clase Controls en MQL5, diseñada para optimizar las operaciones bursátiles. El panel incluye un título, botones de navegación para Operar, Cerrar e Información, y botones de acción especializados para ejecutar operaciones y gestionar posiciones. Al final del artículo, tendrás un panel base listo para futuras mejoras en futuras entregas.
Del básico al intermedio: Plantilla y Typename (III) Del básico al intermedio: Plantilla y Typename (III)
En este artículo, veremos la primera parte de algo que es muy confuso para que los principiantes lo entiendan. Para que el tema no se vuelva más confuso de lo necesario y quede debidamente explicado, dividiré la explicación en etapas. La primera etapa es la que se mostrará en este artículo. No obstante, aunque parezca que llegamos a un callejón sin salida al final, no será realmente eso lo que estará ocurriendo, ya que el siguiente paso nos llevará a otra situación, que se entenderá mejor en el próximo artículo.
Integración de MQL5 con paquetes de procesamiento de datos (Parte 3): Visualización mejorada de datos Integración de MQL5 con paquetes de procesamiento de datos (Parte 3): Visualización mejorada de datos
En este artículo, realizaremos una visualización de datos mejorada que va más allá de los gráficos básicos, incorporando características como interactividad, datos en capas y elementos dinámicos, lo que permite a los operadores explorar tendencias, patrones y correlaciones de manera más eficaz.
Añadimos un LLM personalizado a un robot comercial (Parte 5): Desarrolla y prueba una estrategia de trading con LLMs (II), LoRA-Tuning Añadimos un LLM personalizado a un robot comercial (Parte 5): Desarrolla y prueba una estrategia de trading con LLMs (II), LoRA-Tuning
Con el rápido desarrollo de la inteligencia artificial en la actualidad, los modelos lingüísticos (LLM) son una parte importante de la inteligencia artificial, por lo que deberíamos pensar en cómo integrar potentes LLM en nuestras operaciones algorítmicas. Para la mayoría de la gente, es difícil ajustar estos potentes modelos a sus necesidades, desplegarlos localmente y luego aplicarlos a la negociación algorítmica. Esta serie de artículos adoptará un enfoque paso a paso para lograr este objetivo.