
Asistente de Connexus (Parte 5): Métodos HTTP y códigos de estado
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é es el cuerpo de una solicitud y cómo enviar datos al servidor, y al final, desarrollamos soporte para solicitudes con un cuerpo.
En este quinto artículo de la serie sobre la construcción de la biblioteca Connexus, cubriremos un aspecto esencial del protocolo HTTP: métodos y códigos de estado. Comprender cómo funciona cada verbo HTTP y cómo manejar los códigos de estado es crucial para crear interacciones confiables entre clientes y servidores. ¡Vamos!
Métodos HTTP
Los métodos HTTP son las acciones que le pedimos al servidor que realice. Cuando realizas una solicitud HTTP, como acceder a una página o enviar datos, estás "hablando" con el servidor utilizando estos verbos. A continuación se enumeran los principales:
- GET: Esto es el clásico «dame eso». El navegador solicita ver algo en el servidor, ya sea una página, una imagen o un archivo. Simplemente obtiene la información, sin cambiar nada. Es como pedir el menú de un restaurante, solo para ver qué ofrecen.
- POST: POST es el tipo que entrega un paquete. Aquí estás enviando datos al servidor. Esto es común en los formularios, como cuando te registras en un sitio web. Piénsalo como si estuvieras enviando una carta: esperas a que llegue a su destino y haces algo allí, como registrarte.
- PUT: Cuando utilizas PUT, básicamente estás diciendo: «cambia esto aquí por esta nueva versión». Se utiliza para actualizar un recurso existente. Es como cambiar el aceite de tu coche: es el mismo coche, pero ahora con algo nuevo.
- DELETE: Bastante sencillo, ¿verdad? Es «quita eso de ahí». Le estás pidiendo al camarero que elimine algo. Adiós, hasta nunca más.
- PATCH: PATCH es más delicado. Sólo cambia parte del recurso. Es como arreglar una parte rota de un juguete: no tienes que cambiar todo, sólo ajustar lo que está roto.
- HEAD: Esto es GET, pero sin el cuerpo. Solo desea la información del encabezado, no el contenido. Es como leer el título de un libro sin abrir las páginas.
Existen otros métodos como CONNECT, OPTIONS y TRACE, pero rara vez se utilizan en el trabajo diario de los desarrolladores. No mencionaré detalles de cada uno aquí, pero mi objetivo con la biblioteca es que pueda soportar todos los métodos HTTP. Si desea obtener más información sobre todos los métodos HTTP, acceda a la documentación completa del protocolo aquí. Pero créanme, las solicitudes más comunes en el trabajo diario de los desarrolladores, como GET, POST y DELETE, son suficientes para la mayoría de los problemas.
Quiero enfatizar que solo utilizamos un método por solicitud, es decir, una solicitud no puede ser de tipo GET y POST al mismo tiempo.
Creando la clase CHttpMethod
Ahora que entendemos cada método HTTP, para qué sirve y cuándo usar cada uno, vayamos directamente al código. Implementaremos en Connexus una clase encargada de almacenar el método HTTP que se utilizará para realizar las peticiones. Esta será una clase muy sencilla, independientemente de tu nivel de programación, entenderás la mayor parte de lo que está sucediendo. El propósito de la clase es solo almacenar el método utilizado, pero como estamos en una clase, agregaremos más características para que sea lo más fácil posible para el usuario final de la biblioteca Connexus.
Comencemos creando una nueva carpeta llamada Constants, dentro de ella un nuevo archivo llamado CHttpMethod, al final la ruta quedará así: Include/Constants/HttpMethod.mqh . Dentro de este nuevo archivo crearemos la clase CHttpMethod:
//+------------------------------------------------------------------+ //| HttpMethods.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpMethods | //| | //| [PROPERTY] | //| Name : CHttpMethods | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { public: CHttpMethod(void); ~CHttpMethod(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(void) { } //+------------------------------------------------------------------+
Para contener todos los métodos HTTP posibles, creemos un enum que contenga todos los métodos posibles de una solicitud HTTP. Añadamos también a la clase una nueva variable del tipo ENUM_HTTP_METHOD, llamada m_method:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_HTTP_METHOD { HTTP_METHOD_NULL = 0, // [0] Null HTTP_METHOD_CONNECT, // [1] Connect HTTP_METHOD_DELETE, // [2] Delete HTTP_METHOD_GET, // [3] Get HTTP_METHOD_HEAD, // [4] Head HTTP_METHOD_OPTION, // [5] Option HTTP_METHOD_PATCH, // [6] Patch HTTP_METHOD_POST, // [7] Post HTTP_METHOD_PUT, // [8] Put HTTP_METHOD_TRACE, // [9] Trace }; //+------------------------------------------------------------------+ //| class : CHttpMethods | //| | //| [PROPERTY] | //| Name : CHttpMethods | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { private: ENUM_HTTP_METHOD m_method; // Stores the method that will be used }; //+------------------------------------------------------------------+
Ahora que tenemos la variable que se utilizará para el almacenamiento, creemos métodos auxiliares para definir y recuperar el método HTTP, además de sobrecargar el operador = para facilitar su uso, funciones principales:
- Operador de asignación (operator= ): Permite definir el método HTTP utilizando directamente el operator=.
- SetMethod(ENUM_HTTP_METHOD) y SetMethod(cadena): Define el método HTTP mediante una enumeración o una cadena. Cuando el parámetro es de tipo cadena, utiliza la función StringToUpper() para formar la cadena correctamente.
- GetMethod() y GetMethodDescription(): Obtienen el método HTTP y su descripción textual.
- void operator=(ENUM_HTTP_METHOD method): Se trata de una operación sobrecargada, pero en términos sencillos, se utiliza para definir el método HTTP utilizando operator=. A continuación se muestra un ejemplo de este operador en la práctica:
CHttpMethod method; method = HTTP_METHOD_POST;
- Funciones de verificación (IsPost(), IsGet(), etc.): Facilitan la verificación del método, haciendo que el código sea más legible y simplificado. Un ejemplo de cómo estas funciones pueden ayudarnos:
CHttpMethod method; method.SetMethod("POST") if(method.GetMethod() == HTTP_METHOD_POST) { //--- Action } //--- Or if(method.IsPost()) { //--- Action }
De esta manera evitamos comparaciones explícitas de métodos.
//+------------------------------------------------------------------+ //| class : CHttpMethod | //| | //| [PROPERTY] | //| Name : CHttpMethod | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { private: ENUM_HTTP_METHOD m_method; // Stores the method that will be used public: CHttpMethod(void); ~CHttpMethod(void); //--- Get and set void operator=(ENUM_HTTP_METHOD method); void Set(ENUM_HTTP_METHOD method); bool Set(string method); ENUM_HTTP_METHOD Get(void); string GetAsString(void); //--- Check method bool IsConnect(void); bool IsGet(void); bool IsPost(void); bool IsPut(void); bool IsDelete(void); bool IsPatch(void); bool IsHead(void); bool IsOption(void); bool IsTrace(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ void CHttpMethod::operator=(ENUM_HTTP_METHOD method) { m_method = method; } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ void CHttpMethod::Set(ENUM_HTTP_METHOD method) { m_method = method; } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ bool CHttpMethod::Set(string method) { string method_upper = method; StringToUpper(method_upper); if(method_upper == "CONNECT") { m_method = HTTP_METHOD_CONNECT; return(true); } else if(method_upper == "DELETE") { m_method = HTTP_METHOD_DELETE; return(true); } else if(method_upper == "GET") { m_method = HTTP_METHOD_GET; return(true); } else if(method_upper == "HEAD") { m_method = HTTP_METHOD_HEAD; return(true); } else if(method_upper == "OPTIONS") { m_method = HTTP_METHOD_OPTION; return(true); } else if(method_upper == "PATCH") { m_method = HTTP_METHOD_PATCH; return(true); } else if(method_upper == "POST") { m_method = HTTP_METHOD_POST; return(true); } else if(method_upper == "PUT") { m_method = HTTP_METHOD_PUT; return(true); } else if(method_upper == "TRACE") { m_method = HTTP_METHOD_TRACE; return(true); } return(false); } //+------------------------------------------------------------------+ //| Get http method | //+------------------------------------------------------------------+ ENUM_HTTP_METHOD CHttpMethod::Get(void) { return(m_method); } //+------------------------------------------------------------------+ //| Get the description of the selected http method | //+------------------------------------------------------------------+ string CHttpMethod::GetAsString(void) { switch(m_method) { case HTTP_METHOD_NULL: return "NULL"; case HTTP_METHOD_CONNECT: return "CONNECT"; case HTTP_METHOD_DELETE: return "DELETE"; case HTTP_METHOD_GET: return "GET"; case HTTP_METHOD_HEAD: return "HEAD"; case HTTP_METHOD_OPTION: return "OPTIONS"; case HTTP_METHOD_PATCH: return "PATCH"; case HTTP_METHOD_POST: return "POST"; case HTTP_METHOD_PUT: return "PUT"; case HTTP_METHOD_TRACE: return "TRACE"; default: return "Unknown HTTP Method"; } } //+------------------------------------------------------------------+ //| Check if method is connect | //+------------------------------------------------------------------+ bool CHttpMethod::IsConnect(void) { return(m_method == HTTP_METHOD_CONNECT); } //+------------------------------------------------------------------+ //| Check if method is get | //+------------------------------------------------------------------+ bool CHttpMethod::IsGet(void) { return(m_method == HTTP_METHOD_GET); } //+------------------------------------------------------------------+ //| Check if method is post | //+------------------------------------------------------------------+ bool CHttpMethod::IsPost(void) { return(m_method == HTTP_METHOD_POST); } //+------------------------------------------------------------------+ //| Check if method is put | //+------------------------------------------------------------------+ bool CHttpMethod::IsPut(void) { return(m_method == HTTP_METHOD_PUT); } //+------------------------------------------------------------------+ //| Check if method is delete | //+------------------------------------------------------------------+ bool CHttpMethod::IsDelete(void) { return(m_method == HTTP_METHOD_DELETE); } //+------------------------------------------------------------------+ //| Check if method is patch | //+------------------------------------------------------------------+ bool CHttpMethod::IsPatch(void) { return(m_method == HTTP_METHOD_PATCH); } //+------------------------------------------------------------------+ //| Check if method is head | //+------------------------------------------------------------------+ bool CHttpMethod::IsHead(void) { return(m_method == HTTP_METHOD_HEAD); } //+------------------------------------------------------------------+ //| Check if method is option | //+------------------------------------------------------------------+ bool CHttpMethod::IsOption(void) { return(m_method == HTTP_METHOD_OPTION); } //+------------------------------------------------------------------+ //| Check if method is trace | //+------------------------------------------------------------------+ bool CHttpMethod::IsTrace(void) { return(m_method == HTTP_METHOD_TRACE); } //+------------------------------------------------------------------+
Con esto concluye la clase responsable de almacenar el método HTTP utilizado. Tenemos algunas funciones auxiliares para ahorrar algo de código en el futuro. Pasemos a la siguiente clase auxiliar.
Código de estado
Los códigos de estado son, simplemente, números. Este número está estandarizado y es enviado por el servidor al cliente después de procesar una solicitud. Cada código tiene tres dígitos, el primero indica la categoría a la que pertenece el estado (1xx, 2xx, 3xx, 4xx y 5xx). Este código simplemente le indica cuál fue el resultado de la solicitud, si se completó correctamente, si se generó un error en el lado del servidor o si la solicitud se envió incorrectamente. Hay varios códigos de estado. Este número puede variar entre 100 y 599, y se separan en 5 categorías. Para saber en qué categoría se encuentra el código, simplemente identifique en qué rango se encuentra, vea la tabla con los valores:
Código de estado de rango | Descripción |
---|---|
100-199 | No es muy común verlo. Son respuestas como “estoy procesando, por favor espere”. Es el servidor que dice que está trabajando en tu solicitud, pero que aún no ha terminado. |
200-299 | ¡Ah, esta es la respuesta que más nos gusta! Significa que todo salió bien. El más famoso es el 200 OK, señal de que “todo ha ido bien”. Tú lo pediste y lo recibiste. Así de simple. |
300-399 | El servidor básicamente te está diciendo, “Ups, estás en el lugar equivocado, ve allí”. "301 Moved Permanently" es la redirección permanente, mientras que "302 Found" es temporal, algo así como, “Estoy en renovación, pero puedes encontrar esto aquí por ahora”. |
400-499 | Éstos son los infames errores que nosotros como usuarios a menudo provocamos. El más conocido es el "404 Not Found", cuando la página que estás buscando simplemente no existe. Es como llegar a una dirección y descubrir que el edificio ha sido demolido. |
500-599 | Ahora, cuando el problema está del otro lado, la culpa recae en el servidor. El famoso error interno del servidor 500 es básicamente el servidor dándose por vencido y diciendo “algo salió mal aquí”. |
Hay varios códigos posibles, no los cubriré todos para no hacer el artículo demasiado largo. Si desea obtener más información sobre todos los valores posibles, lea aquí, donde se explica cada código posible en detalle. Vale la pena leerlo si desea obtener más información sobre el protocolo HTTP. En la vida diaria de un desarrollador, solo se utilizan unos pocos códigos y la mayoría de ellos rara vez se encuentran en la web. Enumeraré los más comunes:
1xx: Informativo
- 100 Continue: El servidor recibió los encabezados y el cliente puede continuar enviando el cuerpo de la solicitud.
- 101 Switching Protocols: El cliente solicitó un cambio de protocolo y el servidor lo aceptó.
2xx: Éxito
- 200 OK: La solicitud se ha realizado correctamente.
- 201 Created: La solicitud se ha completado con éxito y se ha creado un nuevo recurso. - 204 No Content: La solicitud se ha realizado correctamente, pero no hay contenido en el cuerpo de la respuesta.
3xx: Redirección
- 301 Moved Permanently: El recurso se ha trasladado de forma permanente a una nueva URL.
- 302 Found: El recurso se ha trasladado temporalmente a una nueva URL.
- 304 Not Modified: El recurso no se ha modificado desde la última solicitud, lo que permite al cliente utilizar la versión almacenada en caché.
4xx: Errores del cliente
- 400 Bad Request: La solicitud no es válida o tiene un formato incorrecto.
- 401 Unauthorized: El acceso no está autorizado; se requiere autenticación.
- 403 Forbidden: El servidor ha entendido la solicitud, pero deniega el acceso.
- 404 Not Found: El recurso solicitado no se encontró.
- 405 Method Not Allowed: El método HTTP utilizado no está permitido para el recurso solicitado.
5xx: Errores del servidor
- 500 Internal Server Error: Se ha producido un error genérico en el servidor.
- 502 Bad Gateway: El servidor recibió una respuesta no válida al intentar satisfacer la solicitud.
- 503 Service Unavailable: El servidor no está disponible temporalmente, normalmente debido a una sobrecarga o a tareas de mantenimiento.
- 504 Gateway Timeout: El servidor no recibió una respuesta a tiempo de otro servidor al que estaba intentando conectarse.
Ahora que entendemos todas las categorías de estado y las más utilizadas, quiero que la biblioteca admita todos los estados posibles. Para ello, trabajaremos sobre una clase capaz de procesar cualquier código de estado recibido por el servidor, siempre que sea válido.
Creación de la clase CHttpStatusCode
Ahora que conocemos todos los códigos de estado posibles, agreguemos la implementación adecuada a la biblioteca. El objetivo aquí es simple: crear una clase que será responsable de almacenar el código de estado recibido. La clase también debe contener soporte para describir cada estado y también debería ser posible identificar rápidamente a qué categoría pertenece ese estado.
Vamos al código. Dentro de esta misma carpeta creada previamente para la clase CHttpMethod, crearemos un nuevo archivo llamado HttpStatusCode.mqh . Al final, la ruta completa será "Includes/Connexus/Constants/HttpStatusCode.mqh".
//+------------------------------------------------------------------+ //| HttpStatusCode.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+
Para contener todos los códigos de estado posibles, crearemos una enumeración con todos los valores posibles. El nombre de la enumeración será ENUM_HTTP_STATUS, el valor de la enumeración será el código de estado respectivo.
enum ENUM_HTTP_STATUS { //--- Mql error HTTP_STATUS_URL_NOT_ALLOWED = -1, HTTP_STATUS_URL_NOT_DEFINED = 1, HTTP_STATUS_METHOD_NOT_DEFINED = 2, //--- Informational HTTP_STATUS_CONTINUE = 100, HTTP_STATUS_SWITCHING_PROTOCOLS = 101, HTTP_STATUS_PROCESSING = 102, HTTP_STATUS_EARLY_HINTS = 103, //--- Successul HTTP_STATUS_OK = 200, HTTP_STATUS_CREATED = 201, HTTP_STATUS_ACCEPTED = 202, HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, HTTP_STATUS_NO_CONTENT = 204, HTTP_STATUS_RESET_CONTENT = 205, HTTP_STATUS_PARTIAL_CONTENT = 206, HTTP_STATUS_MULTI_STATUS = 207, HTTP_STATUS_ALREADY_REPORTED = 208, //--- Redirection messages HTTP_STATUS_MULTIPLE_CHOICES = 300, HTTP_STATUS_MOVED_PERMANENTLY = 301, HTTP_STATUS_FOUND = 302, HTTP_STATUS_SEE_OTHER = 303, HTTP_STATUS_NOT_MODIFIED = 304, HTTP_STATUS_USE_PROXY = 305, HTTP_STATUS_SWITCH_PROXY = 306, HTTP_STATUS_TEMPORARY_REDIRECT = 307, HTTP_STATUS_PERMANENT_REDIRECT = 308, //--- Client error HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_UNAUTHORIZED = 401, HTTP_STATUS_PAYMENT_REQUIRED = 402, HTTP_STATUS_FORBIDDEN = 403, HTTP_STATUS_NOT_FOUND = 404, HTTP_STATUS_METHOD_NOT_ALLOWED = 405, HTTP_STATUS_NOT_ACCEPTABLE = 406, HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, HTTP_STATUS_REQUEST_TIMEOUT = 408, HTTP_STATUS_CONFLICT = 409, HTTP_STATUS_GONE = 410, HTTP_STATUS_LENGTH_REQUIRED = 411, HTTP_STATUS_PRECONDITION_FAILED = 412, HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, HTTP_STATUS_URI_TOO_LONG = 414, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, HTTP_STATUS_EXPECTATION_FAILED = 417, HTTP_STATUS_MISDIRECTED_REQUEST = 421, HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, HTTP_STATUS_LOCKED = 423, HTTP_STATUS_FAILED_DEPENDENCY = 424, HTTP_STATUS_TOO_EARLY = 425, HTTP_STATUS_UPGRADE_REQUIRED = 426, HTTP_STATUS_PRECONDITION_REQUIRED = 428, HTTP_STATUS_TOO_MANY_REQUESTS = 429, HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, //--- Server error HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, HTTP_STATUS_NOT_IMPLEMENTED = 501, HTTP_STATUS_BAD_GATEWAY = 502, HTTP_STATUS_SERVICE_UNAVAILABLE = 503, HTTP_STATUS_GATEWAY_TIMEOUT = 504, HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, HTTP_STATUS_INSUFFICIENT_STORAGE = 507, HTTP_STATUS_LOOP_DETECTED = 508, HTTP_STATUS_NOT_EXTENDED = 510, HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511 };
Tenga en cuenta que agregué algunos comentarios que separan las categorías de cada estado. Tenga en cuenta los primeros valores de la enumeración, agregué estos valores como un “código de estado personalizado”, que será generado automáticamente por la biblioteca, son:
- HTTP_STATUS_URL_NOT_ALLOWED: La URL no se ha añadido a la lista de URL permitidas en el terminal.
- HTTP_STATUS_URL_NOT_DEFINED: La URL no se definió en la solicitud.
- HTTP_STATUS_METHOD_NOT_DEFINED: No se ha definido un método válido para la solicitud.
Cuando se llama a la función WebRequest y devuelve -1, significa que la URL no se añade al terminal, tal y como se indica en la documentación de MQL5, por lo que la biblioteca debería devolver automáticamente "HTTP_STATUS_URL_NOT_ALLOWED". Se aplicará una lógica similar a los demás códigos personalizados, pero no nos centraremos en ellos por ahora.
Continuemos con el desarrollo de la clase, esta clase será similar a CHttpMethod, agregaremos una nueva variable privada llamada m_status de tipo ENUM_HTTP_STATUS, y también agregaremos algunos métodos auxiliares para establecer y obtener el valor de esta variable:
- operator=(int) y operator=(ENUM_HTTP_STATUS): Establece el valor de m_status utilizando operator=, recibiendo un valor entero o un valor enumerado.
- Set(ENUM_HTTP_STATUS): Establece el código de estado utilizando un valor enumerado.
- Get() and GetMessage(): Devuelve el código de estado actual o solo el mensaje correspondiente al código almacenado.
A continuación se muestra el código con la implementación de estos métodos:
//+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { private: ENUM_HTTP_STATUS m_status; // Stores the status used public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); //--- Set void operator=(int status); void operator=(ENUM_HTTP_STATUS status); void Set(ENUM_HTTP_STATUS status); //--- Get ENUM_HTTP_STATUS Get(void); string GetMessage(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Assignment operator to set status from integer value | //+------------------------------------------------------------------+ void CHttpStatusCodes::operator=(int status) { m_status = (ENUM_HTTP_STATUS)status; } //+------------------------------------------------------------------+ //| Assignment operator to set status from ENUM_HTTP_STATUS | //+------------------------------------------------------------------+ void CHttpStatusCodes::operator=(ENUM_HTTP_STATUS status) { m_status = status; } //+------------------------------------------------------------------+ //| Sets the HTTP status code | //+------------------------------------------------------------------+ void CHttpStatusCodes::Set(ENUM_HTTP_STATUS status) { m_status = status; } //+------------------------------------------------------------------+ //| Returns the stored HTTP status code | //+------------------------------------------------------------------+ ENUM_HTTP_STATUS CHttpStatusCodes::Get(void) { return(m_status); } //+------------------------------------------------------------------+ //| Returns a message corresponding to the stored HTTP status code | //+------------------------------------------------------------------+ string CHttpStatusCodes::GetMessage(void) { switch(m_status) { case HTTP_STATUS_URL_NOT_ALLOWED: return "The URL was not added to the list of allowed URLs in the terminal"; case HTTP_STATUS_URL_NOT_DEFINED: return "URL was not defined in the request"; case HTTP_STATUS_METHOD_NOT_DEFINED: return "Method was not defined in the request"; case HTTP_STATUS_CONTINUE: return "Continue"; case HTTP_STATUS_SWITCHING_PROTOCOLS: return "Switching Protocols"; case HTTP_STATUS_PROCESSING: return "Processing"; case HTTP_STATUS_EARLY_HINTS: return "Early Hints"; case HTTP_STATUS_OK: return "OK"; case HTTP_STATUS_CREATED: return "Created"; case HTTP_STATUS_ACCEPTED: return "Accepted"; case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information"; case HTTP_STATUS_NO_CONTENT: return "No Content"; case HTTP_STATUS_RESET_CONTENT: return "Reset Content"; case HTTP_STATUS_PARTIAL_CONTENT: return "Partial Content"; case HTTP_STATUS_MULTI_STATUS: return "Multi-Status"; case HTTP_STATUS_ALREADY_REPORTED: return "Already Reported"; case HTTP_STATUS_MULTIPLE_CHOICES: return "Multiple Choices"; case HTTP_STATUS_MOVED_PERMANENTLY: return "Moved Permanently"; case HTTP_STATUS_FOUND: return "Found"; case HTTP_STATUS_SEE_OTHER: return "See Other"; case HTTP_STATUS_NOT_MODIFIED: return "Not Modified"; case HTTP_STATUS_USE_PROXY: return "Use Proxy"; case HTTP_STATUS_SWITCH_PROXY: return "Switch Proxy"; case HTTP_STATUS_TEMPORARY_REDIRECT: return "Temporary Redirect"; case HTTP_STATUS_PERMANENT_REDIRECT: return "Permanent Redirect"; case HTTP_STATUS_BAD_REQUEST: return "Bad Request"; case HTTP_STATUS_UNAUTHORIZED: return "Unauthorized"; case HTTP_STATUS_PAYMENT_REQUIRED: return "Payment Required"; case HTTP_STATUS_FORBIDDEN: return "Forbidden"; case HTTP_STATUS_NOT_FOUND: return "Not Found"; case HTTP_STATUS_METHOD_NOT_ALLOWED: return "Method Not Allowed"; case HTTP_STATUS_NOT_ACCEPTABLE: return "Not Acceptable"; case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required"; case HTTP_STATUS_REQUEST_TIMEOUT: return "Request Timeout"; case HTTP_STATUS_CONFLICT: return "Conflict"; case HTTP_STATUS_GONE: return "Gone"; case HTTP_STATUS_LENGTH_REQUIRED: return "Length Required"; case HTTP_STATUS_PRECONDITION_FAILED: return "Precondition Failed"; case HTTP_STATUS_PAYLOAD_TOO_LARGE: return "Payload Too Large"; case HTTP_STATUS_URI_TOO_LONG: return "URI Too Long"; case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type"; case HTTP_STATUS_RANGE_NOT_SATISFIABLE: return "Range Not Satisfiable"; case HTTP_STATUS_EXPECTATION_FAILED: return "Expectation Failed"; case HTTP_STATUS_MISDIRECTED_REQUEST: return "Misdirected Request"; case HTTP_STATUS_UNPROCESSABLE_ENTITY: return "Unprocessable Entity"; case HTTP_STATUS_LOCKED: return "Locked"; case HTTP_STATUS_FAILED_DEPENDENCY: return "Failed Dependency"; case HTTP_STATUS_TOO_EARLY: return "Too Early"; case HTTP_STATUS_UPGRADE_REQUIRED: return "Upgrade Required"; case HTTP_STATUS_PRECONDITION_REQUIRED: return "Precondition Required"; case HTTP_STATUS_TOO_MANY_REQUESTS: return "Too Many Requests"; case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: return "Request Header Fields Too Large"; case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: return "Unavailable For Legal Reasons"; case HTTP_STATUS_INTERNAL_SERVER_ERROR: return "Internal Server Error"; case HTTP_STATUS_NOT_IMPLEMENTED: return "Not Implemented"; case HTTP_STATUS_BAD_GATEWAY: return "Bad Gateway"; case HTTP_STATUS_SERVICE_UNAVAILABLE: return "Service Unavailable"; case HTTP_STATUS_GATEWAY_TIMEOUT: return "Gateway Timeout"; case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported"; case HTTP_STATUS_VARIANT_ALSO_NEGOTIATES: return "Variant Also Negotiates"; case HTTP_STATUS_INSUFFICIENT_STORAGE: return "Insufficient Storage"; case HTTP_STATUS_LOOP_DETECTED: return "Loop Detected"; case HTTP_STATUS_NOT_EXTENDED: return "Not Extended"; case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED: return "Network Authentication Required"; default: return "Unknown HTTP Status"; } } //+------------------------------------------------------------------+
Añadamos algunos métodos auxiliares más, que se encargarán de comprobar si el código de estado almacenado en la clase pertenece a una categoría específica. Estos son:
- bool IsInformational(void): Rango informativo (100 - 199)
- bool IsSuccess(void): Rango de éxito (200 - 299)
- bool IsRedirection(void): Rango de redireccionamiento (300 - 399)
- bool IsClientError(void): Rango de errores del cliente (400 - 499)
- bool IsServerError(void): Rango de errores del servidor (500 - 599)
//+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { private: ENUM_HTTP_STATUS m_status; // Stores the status used public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); //--- Check which group the code is in bool IsInformational(void); // Checks if the status code is in the informational response range (100 - 199) bool IsSuccess(void); // Check if the status code is in the success range (200 - 299) bool IsRedirection(void); // Check if the status code is in the redirect range (300 - 399) bool IsClientError(void); // Checks if the status code is in the client error range (400 - 499) bool IsServerError(void); // Check if the status code is in the server error range (500 - 599) }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Checks if the status code is in the informational response | //| range (100 - 199) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsInformational(void) { return(m_status >= 100 && m_status <= 199); } //+------------------------------------------------------------------+ //| Check if the status code is in the success range (200 - 299) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsSuccess(void) { return(m_status >= 200 && m_status <= 299); } //+------------------------------------------------------------------+ //| Check if the status code is in the redirect range (300 - 399) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsRedirection(void) { return(m_status >= 300 && m_status <= 399); } //+------------------------------------------------------------------+ //| Checks if the status code is in the client error range | //| (400 - 499) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsClientError(void) { return(m_status >= 400 && m_status <= 499); } //+------------------------------------------------------------------+ //| Check if the status code is in the server error range (500 - 599)| //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsServerError(void) { return(m_status >= 500 && m_status <= 599); } //+------------------------------------------------------------------+
Conclusión
Para hacer más visual el progreso de la biblioteca, siga el diagrama a continuación:
Tenemos todas las clases auxiliares listas, que se encargan de manejar cada elemento HTTP de forma independiente. Tenemos las clases CQueryParam, CHttpHeader y CHttpBody que utilizan la clase CJson, pero no existe una relación de herencia entre ellas. Las clases creadas en este artículo aún no se han conectado con las demás, en el próximo artículo conectaremos todo creando una solicitud y respuesta HTTP.
En este artículo entenderemos los métodos HTTP y también los códigos de estado, dos piezas muy importantes para la comunicación web entre cliente y servidor. Comprender lo que hace cada método le brinda el control para realizar solicitudes con mayor precisión, informando al servidor qué acción desea realizar y haciéndolo más eficiente. Cada método tiene un papel en la comunicación y usarlo correctamente hace que la comunicación con la API sea más clara, tanto para el cliente como para el servidor, sin sorpresas.
Además, hablamos de códigos de estado, que son la respuesta directa del servidor sobre lo que sucedió con la solicitud. Estos varían desde un simple “todo bien” (200 OK) hasta mensajes de error del lado del cliente (4xx) o del lado del servidor (5xx). Saber cómo manejar estos códigos es una habilidad valiosa, porque a menudo un error no significa el final del camino, sino más bien una oportunidad para ajustar o intentarlo de nuevo.
Durante este proceso de construcción de la biblioteca Connexus, aprendimos a manejar cada uno de estos elementos, lo que hace que nuestra biblioteca sea más robusta y capaz de manejar los matices de la comunicación HTTP. Desde aquí, nuestra clase responsable de los métodos y códigos de estado estará lista para brindar al desarrollador un mayor nivel de control y seguridad al interactuar con las API.
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16136





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso