
Título no Connexus (Parte 3): dominando o uso de cabeçalhos HTTP em requisições
Introdução
Este artigo é uma continuação da série em que estamos criando uma biblioteca chamada Connexus. No primeiro artigo, compreendemos os fundamentos da função WebRequest, analisamos cada um de seus parâmetros e criamos um exemplo de código que demonstra como utilizá-la e as dificuldades envolvidas. Neste artigo, veremos a importância e a utilidade dos cabeçalhos na comunicação HTTP e como esses elementos são utilizados para diferentes finalidades na internet moderna.
A estrutura de uma mensagem HTTP, seja de resposta ou de requisição, é composta por dois elementos principais, que exploraremos com mais detalhes: cabeçalhos e corpo. Cada um deles desempenha um papel importante no processo de comunicação, garantindo uma transmissão de dados organizada, eficiente e segura.
Para começar, revisaremos brevemente como funciona a estrutura das requisições e respostas HTTP.
Estrutura de uma requisição HTTP
Uma requisição HTTP geralmente segue o seguinte formato:
HTTP Method | URL | HTTP Version Headers Body (Optional)
- Método HTTP: define o propósito da requisição (GET, POST, PUT, DELETE etc.).
- URL: identifica o recurso solicitado. (Discutimos isso com mais detalhes no artigo anterior)
- Versão do HTTP: indica a versão do protocolo usada.
- Cabeçalhos: solicitam metadados, como tipo de conteúdo, autenticação etc.
- Corpo: o conteúdo da requisição, normalmente presente em métodos como POST ou PUT
Estrutura de uma resposta HTTP
A resposta HTTP tem uma estrutura semelhante:
HTTP Version | Status Code | Status Message Headers Body (Optional)
- Código de status: indica o resultado (200 OK, 404 Not Found, 500 Internal Server Error, etc.).
- Cabeçalhos: informações sobre o conteúdo retornado, como tamanho, tipo de dado etc.
- Corpo: o conteúdo real da resposta, como o código HTML de uma página ou dados no formato JSON. No nosso caso, geralmente será usado para obter dados no formato JSON, mas tenha em mente que algumas APIs podem retornar HTML.
No artigo anterior, analisamos o formato do endereço URL com mais profundidade, examinando cada elemento separadamente e os agrupando para formar o endereço completo. Neste artigo, vamos focar no cabeçalho da requisição HTTP. Para que ele serve? Como utilizá-lo? Quais são os possíveis valores, entre outros pontos.
Cabeçalhos
Primeiro, vamos entender o que são cabeçalhos. No protocolo HTTP, um cabeçalho é um conjunto de dados enviados junto à requisição ou à resposta. Os cabeçalhos HTTP desempenham um papel importante na interação entre cliente e servidor. Sua função principal é fornecer informações detalhadas sobre a requisição que não fazem parte do endereço URL ou do corpo da mensagem. Eles ajudam a controlar o fluxo da comunicação e fornecem o contexto necessário para que o servidor possa interpretar e processar os dados corretamente. Esses cabeçalhos ajudam tanto o servidor quanto o cliente a entenderem melhor o contexto da requisição ou da resposta, como o tipo de conteúdo, cache, autenticação etc. Em outras palavras, eles atuam como metadados, informando ao servidor como a requisição deve ser tratada e ao cliente como a resposta deve ser interpretada.
Vamos mencionar algumas das funções principais dos cabeçalhos HTTP:
- Autenticação: uma das formas mais comuns de uso dos cabeçalhos é a autenticação do cliente, para que o servidor saiba quem está enviando a requisição e se essa pessoa tem acesso às informações. Por exemplo, o cabeçalho Authorization envia um token ou credenciais que o servidor recebe e pode usar para validar o cliente antes de processar a requisição.
- Gerenciamento de cache: cabeçalhos, como Cache-Control, permitem que o cliente e o servidor configurem como os dados devem ser armazenados em cache. Isso pode ser útil para evitar uma nova requisição desnecessária do cliente para o servidor ou do servidor para algum outro serviço. Os dados em cache podem ser armazenados no próprio cliente, em servidores proxy ou em outros nós intermediários.
- Indicação do tipo de conteúdo: o cabeçalho Content-Type permite que o cliente informe ao servidor o tipo de dado que está sendo enviado ou recebido. Geralmente, são utilizados formatos como JSON, XML ou HTML. Isso garante que ambos os lados da comunicação saibam interpretar os dados corretamente.
- Negociação de conteúdo: o cliente pode usar o cabeçalho Accept para informar ao servidor quais formatos de resposta são aceitáveis, como application/json (o servidor enviará os dados no formato json) ou text/html (o servidor os enviará em formato html). Isso permite que o servidor envie a resposta em um formato que o cliente esteja preparado para receber. O formato mais utilizado é o JSON, e é nele que focaremos aqui, mas outros formatos também são suportados.
- Segurança: cabeçalhos como Strict-Transport-Security ajudam a reforçar o uso do protocolo HTTPS, que é semelhante ao HTTP, mas oferece uma camada adicional de segurança na web. A requisição, a resposta, os cabeçalhos, o corpo, o URL e os outros formatos são exatamente os mesmos, por isso é sempre recomendado usar HTTPS). Outros cabeçalhos, como o CORS (Cross Origin Resource Sharing, Compartilhamento de Recursos entre Origens Diferentes), definem quais domínios podem acessar os recursos da API, aumentando a segurança. Dessa forma, o servidor filtra para quem envia as informações, enviando-as apenas para um domínio previamente definido, de modo que nenhum outro domínio possa acessar esses dados.
- Limitação da quantidade de requisições: alguns serviços retornam os cabeçalhos X-RateLimit-Limit e X-RateLimit-Remaining para informar ao cliente a quantidade de requisições permitidas em um determinado período. Isso evita que o servidor fique sobrecarregado.
Dessa forma, os cabeçalhos são essenciais para a comunicação HTTP, garantindo controle, clareza e segurança sobre como a requisição e a resposta devem ser tratadas.
Conhecimento sobre alguns valores possíveis
Vamos ver quais são os valores possíveis para os cabeçalhos mais comuns. Os cabeçalhos HTTP são muito versáteis e podem ser configurados conforme necessário para a comunicação entre cliente e servidor. Lembre-se de que os valores que um cabeçalho pode conter dependem do contexto da mensagem. Abaixo estão alguns exemplos dos cabeçalhos mais comuns e seus possíveis valores:
- Authorization: usado para enviar credenciais ou tokens de autenticação do cliente para o servidor, permitindo o acesso a recursos protegidos. Pode assumir diferentes valores, dependendo do método de autenticação utilizado. Existem vários métodos de autenticação; vamos considerar os mais utilizados:
-
Token do tipo Bearer (Bearer Token): um dos formatos mais comuns, especialmente em APIs modernas que usam autenticação baseada em token. Esse valor geralmente representa um token JWT (JSON Web Token), obtido pelo cliente após fazer login ou autenticação no servidor de autenticação.
Authorization: Bearer <my_token_jwt>
O valor <my_token_jwt> é o próprio token de autenticação, normalmente uma longa sequência de caracteres codificada em Base64. Esse token contém informações sobre a autorização do usuário e possui um tempo de validade limitado.
-
Basic: esse valor utiliza a autenticação básica HTTP, onde o nome de usuário e a senha são codificados no formato Base64 e enviados diretamente no cabeçalho. Esse método é menos seguro, já que as credenciais podem ser facilmente decodificadas, e não deve ser usado sem HTTPS.
Authorization: Basic base64(username:password)
O valor base64(username:password) é a codificação Base64 do par nome de usuário:senha. Embora esse método seja simples, ele é vulnerável a ataques se não for usado em conexões criptografadas.
-
Digest: um método mais seguro do que o Basic, o Digest usa um hash das credenciais do usuário em vez de enviar os dados diretamente. Embora hoje, com o surgimento do OAuth e do JWT, ele seja menos comum, ainda aparece em algumas APIs.
Authorization: Digest username="admin", realm="example", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", response="6629fae49393a05397450978507c4ef1"
Aqui, o valor contém vários campos, como o nome de usuário, um número único (nonce – número usado uma vez), um realm (área de autenticação) e uma resposta criptografada com hash.
-
- Content-Type: este cabeçalho define o tipo de conteúdo presente no corpo da requisição ou da resposta. Vamos analisar alguns dos valores mais utilizados:
-
application/json: é o valor mais comum ao trabalhar com APIs, já que o JSON é um formato leve e de fácil leitura e escrita para troca de dados. Exemplo de uso:
Content-Type: application/json
-
application/xml: XML (Extensible Markup Language – linguagem de marcação extensível) era amplamente usado antes da popularização do JSON e ainda é usado em alguns sistemas legados ou APIs antigas. No entanto, a maioria das APIs modernas já adota o formato JSON, então, por enquanto, não precisamos nos preocupar com XML.
Content-Type: application/xml
-
multipart/form-data: esse valor é usado para enviar dados mistos, especialmente quando o cliente precisa fazer upload de arquivos ou dados de formulário. Este não é o foco do nosso estudo neste momento, mas é bom saber que essa possibilidade existe.
-
text/html: usado quando o conteúdo enviado ou recebido é HTML. Esse valor é comum em requisições e respostas de páginas web.
Content-Type: text/html
-
- User-Agent: esse cabeçalho é usado pelo cliente para se identificar. Normalmente, ele contém informações sobre o tipo de dispositivo, navegador e sistema operacional a partir do qual a requisição está sendo feita. Não há uma regra fixa para os valores, mas alguns padrões são usados:
-
Navegadores web: o valor enviado por navegadores geralmente inclui informações detalhadas sobre o nome e a versão do navegador, bem como o sistema operacional.
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
-
APIs ou Aplicativos: aplicações podem usar um valor personalizado, por exemplo:
User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)
Isso permite que o servidor saiba que a requisição veio de um aplicativo específico, o que facilita a depuração ou o monitoramento, se necessário.
-
- Accept: usado pelo cliente para informar qual tipo de conteúdo ele aceita como resposta. Os valores possíveis para esse cabeçalho são semelhantes aos do Content-Type; vamos revisar alguns deles:
-
application/json, application/xml, text/html: você já os conhece, vimos esses formatos na seção "Content-Type".
-
image/png, image/jpeg, image/webp: esses valores são utilizados quando o cliente espera receber uma imagem. Por exemplo, em APIs que fornecem dados gráficos, como miniaturas ou gráficos gerados. Ou simplesmente imagens como avatar de usuário, logotipo de site, etc.
Accept: image/png, image/jpeg
Aqui o cliente informa que aceita imagens tanto no formato PNG quanto no formato JPEG.
-
*/*: esse valor indica que o cliente aceita qualquer tipo de conteúdo como resposta. É usado quando o cliente não tem preferência por um formato específico ou está preparado para lidar com qualquer tipo de resposta.
-
Como organizar o cabeçalho?
Agora que entendemos para que servem os cabeçalhos e alguns dos valores possíveis, vamos entender como os cabeçalhos são estruturados. Os cabeçalhos são organizados como um conjunto de pares chave-valor e inseridos nas requisições. Embora alguns cabeçalhos sejam obrigatórios para certas operações, a maioria é opcional e depende das exigências do aplicativo. Veja um exemplo básico de cabeçalho em uma requisição HTTP:
GET /api/resource HTTP/1.1 Host: example.com Authorization: Bearer token123 Content-Type: application/json User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)
Como mostrado neste exemplo, temos 3 cabeçalhos:
- Authorization: fornece nosso token de acesso “token123”.
- Content-Type: informa como os dados estão sendo transmitidos, estamos usando JSON
- User-Agent: fornece ao servidor uma identificação sobre como tratar a requisição. Neste exemplo usamos “Connexus/1.0 (MetaTrader 5 Terminal)”
Esses cabeçalhos contêm informações que permitem ao servidor saber como processar a requisição. Esse é apenas um exemplo simples, e em breve vamos analisar com mais detalhes quais conjuntos são mais usados, seus possíveis valores e para que serve cada um deles.
Mãos no código
Já entendemos como os cabeçalhos funcionam, para que servem e como usá-los; agora vamos para a parte prática. Lembra do httpbin? É um serviço gratuito que funciona como um espelho: tudo o que enviamos volta para nós. Vamos usá-lo para verificar quais cabeçalhos estamos enviando e se há cabeçalhos que o próprio terminal adiciona automaticamente. Para isso, vamos criar um arquivo com o nome TestHeader.mq5 dentro da pasta Experts/Connexus/Test/TestHeader.mq5. Vamos criar uma requisição POST sem enviar nada nos cabeçalhos e ver o que recebemos como resposta:
#include <Connexus2/Data/Json.mqh> #include <Connexus2/URL/URL.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[]; string headers_send; //--- Data that will be received char body_receive[]; string headers_receive; //--- Send request int status_code = WebRequest(method,url.FullUrl(),headers_send,5000,body_send,body_receive,headers_receive); //--- Show response Print("Respose: ",CharArrayToString(body_receive)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Ao executar esse código no terminal, receberemos a seguinte resposta:
Respose: { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "pt,en;q=0.5", "Content-Length": "0", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "MetaTrader 5 Terminal/5.4518 (Windows NT 11.0.22631; x64)", "X-Amzn-Trace-Id": "Root=1-66feb3d9-50de44d019af8b0c1058436b" }, "json": null, "origin": "189.74.63.39", "url": "https://httpbin.org/post" }
Preste atenção no valor “headers”; ele contém outro objeto json com alguns valores de cabeçalho que são definidos automaticamente pelo terminal. Lembre-se de que, na requisição, não enviamos nenhum dado, nem no cabeçalho nem no corpo. Vamos entender cada um desses cabeçalhos que são enviados automaticamente:
-
Accept: como vimos anteriormente, ele informa ao servidor quais tipos de conteúdo o cliente está preparado para aceitar como resposta. Neste caso, o valor /, como vimos antes, indica que o cliente aceita qualquer tipo de conteúdo como resposta.
-
Accept-Encoding: define os tipos de codificação de conteúdo que o cliente pode aceitar. Codificações são usadas para comprimir os dados com o objetivo de economizar largura de banda da rede.
- gzip: é um formato de compressão usado para reduzir o tamanho da resposta enviada.
- deflate: é outra forma de compressão de dados, parecida com o gzip, mas com algumas diferenças técnicas no algoritmo.
-
Accept-Language: esse cabeçalho informa ao servidor quais idiomas o cliente prefere, mas o servidor deve suportar vários idiomas. Ele ajuda o servidor a fornecer conteúdo no idioma mais adequado para o usuário.
- pt: o cliente prefere receber a resposta em português.
- en;q=0.5: aqui, "en" significa inglês, e "q=0.5" é o "fator de qualidade" (de 0 a 1), indicando a prioridade relativa do idioma. Um valor de q=1.0 seria a preferência máxima, enquanto q=0.5 significa que o cliente aceita inglês, mas prefere português.
-
Content-Length: indica o tamanho do corpo da requisição em bytes. Neste caso, o valor é 0, o que significa que não há conteúdo, como já mencionamos, não estamos enviando dados no corpo da requisição.
-
Content-Type: informa ao servidor o tipo de dados enviados para ele. Neste caso, o valor application/x-www-form-urlencoded indica que os dados foram enviados no formato de formulário codificado por URL. Eu não entendo exatamente por que o MetaTrader 5 define esse formato como padrão.
-
Host: indica o nome do servidor ao qual a requisição está sendo feita. Isso é necessário para que o servidor saiba qual domínio ou IP está sendo solicitado, especialmente se ele atende vários domínios em um único endereço IP.
-
User-Agent: é a string que identifica o cliente HTTP (neste caso, o MetaTrader 5) que está fazendo a requisição. Ela contém informações detalhadas sobre o software utilizado e o sistema operacional.
-
X-Amzn-Trace-Id: o cabeçalho X-Amzn-Trace-Id é usado pelos serviços da AWS (Amazon Web Services) para rastrear requisições dentro da infraestrutura distribuída deles. Isso ajuda a identificar e resolver problemas em aplicações executadas na nuvem da Amazon.
- Root=1-66feb3d9-50de44d019af8b0c1058436b: esse valor representa um identificador único de rastreamento, que pode ser usado para identificar uma transação específica. Ele pode ser utilizado para diagnóstico e monitoramento de funcionamento.
- Meaning: esse identificador é atribuído automaticamente pelo sistema AWS e pode ser usado para rastrear o caminho da requisição enquanto ela passa por diferentes serviços da infraestrutura da Amazon.
- Common usage: esse cabeçalho é usado internamente nos serviços da AWS para coletar informações de rastreamento e monitoramento. Ele é especialmente útil em arquiteturas de microsserviços para diagnosticar gargalos e problemas de latência.
Acredito que o MetaTrader 5 o adiciona automaticamente para poder rastrear as requisições do terminal com fins de diagnóstico, por exemplo, da plataforma, ou para ajudar na correção de algum erro.
Agora que vimos quais cabeçalhos o MetaTrader 5 adiciona por padrão, vamos modificar alguns deles. Lembre-se de que os cabeçalhos não podem ter duas chaves iguais, ou seja, você não pode usar Content-Type: application/json e Content-Type: application/x-www-form-urlencoded ao mesmo tempo. Portanto, se definirmos um novo valor para Content-Type, ele irá sobrescrever o valor anterior. Vamos modificar alguns dados, definindo outros valores para os seguintes cabeçalhos:
- Content-Type: application/json
- User-Agent: connexus/1.0 (MetaTrader 5 Terminal)
Vamos adicionar esses valores à variável “headers_send”, que é uma string. Não se esqueça de adicionar “\n” para separar os cabeçalhos uns dos outros. O código alterado é apresentado abaixo:
#include <Connexus2/Data/Json.mqh> #include <Connexus2/URL/URL.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" string headers_send = "User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)\nContent-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,5000,body_send,body_receive,headers_receive); //--- Show response Print("Respose: ",CharArrayToString(body_receive)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Ao executar o código, teremos o seguinte resultado:
Respose: { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "pt,en;q=0.5", "Content-Length": "0", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", "X-Amzn-Trace-Id": "Root=1-66feb90f-037374b15f220d3e28e1cb32" }, "json": null, "origin": "189.74.63.39", "url": "https://httpbin.org/post" }
Perceba que modificamos os valores de User-Agent e Content-Type para os que definimos. Agora que temos um exemplo simples de requisição enviando alguns cabeçalhos personalizados, vamos adicionar essa funcionalidade de cabeçalhos à nossa biblioteca. Nosso objetivo é criar uma classe para lidar com os cabeçalhos. Essa classe deve ser fácil de usar, ter uma interface simples e intuitiva e permitir adicionar, remover ou atualizar cabeçalhos com facilidade.
Criação da classe HttpHeaders
Vamos criar uma nova pasta dentro da pasta Connexus, que está dentro de Includes. Essa nova pasta será chamada Headers, e dentro dela vamos criar um novo arquivo com o nome HttpHeaders.mqh. No final, o caminho ficará assim:
//+------------------------------------------------------------------+ //| Header.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpHeader | //| | //| [PROPERTY] | //| Name : CHttpHeader | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the headers | //| of a request. | //| | //+------------------------------------------------------------------+ class CHttpHeader { public: CHttpHeader(void); ~CHttpHeader(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpHeader::CHttpHeader(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpHeader::~CHttpHeader(void) { } //+------------------------------------------------------------------+
Para armazenar esses cabeçalhos, vamos utilizar um objeto json, onde a chave do json será a chave do cabeçalho e, da mesma forma, o valor do json será o valor do cabeçalho. Para isso, importaremos a classe json e criaremos dentro dela uma nova instância chamada m_headers.
//+------------------------------------------------------------------+ //| Include the file CJson class | //+------------------------------------------------------------------+ #include "../Data/Json.mqh" //+------------------------------------------------------------------+ //| class : CHttpHeader | //| | //| [PROPERTY] | //| Name : CHttpHeader | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the headers | //| of a request. | //| | //+------------------------------------------------------------------+ class CHttpHeader { private: CJson m_headers; public: CHttpHeader(void); ~CHttpHeader(void); }; //+------------------------------------------------------------------+
Quando o objeto json estiver pronto para armazenar os dados, o próximo passo será definir quais métodos essa classe deve possuir. Inicialmente, vamos criar os seguintes métodos:
- Add(string key, string value): adiciona um novo cabeçalho à requisição HTTP ou o atualiza, se já existir
- Get(string key): retorna o valor de um cabeçalho específico, com base em seu nome
- Remove(string key): remove um cabeçalho específico
- Has(string key): verifica se existe um cabeçalho com a chave indicada
- Clear(): remove todos os cabeçalhos da requisição
- Count(): retorna a quantidade de cabeçalhos
Vamos adicionar esses métodos mais simples à classe
//+------------------------------------------------------------------+ //| class : CHttpHeader | //| | //| [PROPERTY] | //| Name : CHttpHeader | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the headers | //| of a request. | //| | //+------------------------------------------------------------------+ class CHttpHeader { private: CJson m_headers; public: CHttpHeader(void); ~CHttpHeader(void); //--- Functions to manage headers void Add(string key, string value); // Adds a new header to the HTTP request or updates it if it already exists string Get(string key); // Returns the value of a specific header, given its name. void Remove(string key); // Removes a specific header. bool Has(string key); // Checks whether a header with the specified key is present. void Clear(void); // Removes all headers from the request. int Count(void); // Returns the number of headers. }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpHeader::CHttpHeader(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpHeader::~CHttpHeader(void) { } //+------------------------------------------------------------------+ //| Adds a new header to the HTTP request or updates it if it already| //| exists | //+------------------------------------------------------------------+ void CHttpHeader::Add(string key,string value) { m_headers[key] = value; } //+------------------------------------------------------------------+ //| Returns the value of a specific header, given its name. | //+------------------------------------------------------------------+ string CHttpHeader::Get(string key) { return(m_headers[key].ToString()); } //+------------------------------------------------------------------+ //| Removes a specific header. | //+------------------------------------------------------------------+ void CHttpHeader::Remove(string key) { m_headers.Remove(key); } //+------------------------------------------------------------------+ //| Checks whether a header with the specified key is present. | //+------------------------------------------------------------------+ bool CHttpHeader::Has(string key) { return(m_headers.FindKey(key) != NULL); } //+------------------------------------------------------------------+ //| Removes all headers from the request. | //+------------------------------------------------------------------+ void CHttpHeader::Clear(void) { m_headers.Clear(); } //+------------------------------------------------------------------+ //| Returns the number of headers. | //+------------------------------------------------------------------+ int CHttpHeader::Count(void) { return(m_headers.Size()); } //+------------------------------------------------------------------+
Agora que adicionamos os métodos mais básicos, vamos incluir os dois métodos finais, que são o núcleo da classe:
- Serialize(): retorna todos os cabeçalhos em formato de string, prontos para serem enviados em uma requisição HTTP
- Parse(string headers): converte uma string contendo cabeçalhos (normalmente obtidos em uma resposta HTTP) para o formato utilizado na classe
//+------------------------------------------------------------------+ //| class : CHttpHeader | //| | //| [PROPERTY] | //| Name : CHttpHeader | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the headers | //| of a request. | //| | //+------------------------------------------------------------------+ class CHttpHeader { private: CJson m_headers; public: CHttpHeader(void); ~CHttpHeader(void); //--- Auxiliary methods string Serialize(void); // Returns all headers in string format, ready to be sent in an HTTP request. bool Parse(string headers); // Converts a string containing headers (usually received in an HTTP response) into a format usable by the class. }; //+------------------------------------------------------------------+ //| Returns all headers in string format, ready to be sent in an HTTP| //| request. | //+------------------------------------------------------------------+ string CHttpHeader::Serialize(void) { //--- String with the result string headers; //--- Get size int size = this.Count(); for(int i=0;i<size;i++) { //--- Adds the header to the string in the format: "key: value" headers += m_headers[i].m_key + ": " + m_headers[i].ToString(); //--- If it's not the last time it adds "\n" at the end of the string if(i != size -1) { headers += "\n"; } } //--- Return result return(headers); } //+------------------------------------------------------------------+ //| Converts a string containing headers (usually received in an HTTP| //| response) into a format usable by the class. | //+------------------------------------------------------------------+ bool CHttpHeader::Parse(string headers) { //--- Array to store the key value sets string params[]; //--- Separate the string, using the "\n" character as a separator int size = StringSplit(headers,StringGetCharacter("\n",0),params); for(int i=0;i<size;i++) { //--- With the header separated using ": " int pos = StringFind(params[i],": "); if(pos >= 0) { //--- Get key and value string key = StringSubstr(params[i],0,pos); string value = StringSubstr(params[i],pos+2); //--- Clear value StringTrimRight(value); //--- Add in json this.Add(key,value); } } return(true); } //+------------------------------------------------------------------+
Testes
Para realizar os testes da classe, vou utilizar o mesmo arquivo que criamos no início do artigo, o TestHeader.mq5. Vamos importar o arquivo HttpHeader e, em seguida, criar uma instância da classe CHttpHeader, passando os dados para essa classe. Depois, utilizo a função Serialize() para formatá-los como uma string.
#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 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); } //+------------------------------------------------------------------+
Ao executar esse código no terminal, obteremos a mesma resposta:
Respose: { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "pt,en;q=0.5", "Content-Length": "0", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", "X-Amzn-Trace-Id": "Root=1-66fed891-0d6adb5334becd71123795c9" }, "json": null, "origin": "189.74.63.39", "url": "https://httpbin.org/post" }
Considerações finais
Resumidamente, os cabeçalhos HTTP são como bilhetinhos que você passa durante a aula para que o servidor saiba o que fazer com sua requisição. Eles podem autenticar, definir o tipo de conteúdo, dar instruções de cache e muito mais. Sem eles, a comunicação pelo protocolo HTTP seria tão caótica quanto tentar pedir um café sem dizer o tamanho, a quantidade de açúcar ou o tipo de leite. Atualmente, o diagrama de classes que criamos está assim:
Agora que você já entendeu os cabeçalhos e o quanto eles são importantes, é hora de mergulhar em algo ainda mais interessante: o corpo da requisição. No próximo artigo, vamos abordar o núcleo da interação HTTP – o conteúdo real que será enviado ao servidor. Afinal, não faz sentido enviar um bilhete sem conteúdo, certo?
Prepare-se, na próxima parte vamos ver como empacotar essas informações de forma elegante e eficiente no corpo da mensagem. Até lá!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16043
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso