English Русский 中文 Español 日本語 Português
preview
Der Header im Connexus (Teil 3): Die Verwendung von HTTP-Headern für Anfragen beherrschen

Der Header im Connexus (Teil 3): Die Verwendung von HTTP-Headern für Anfragen beherrschen

MetaTrader 5Beispiele |
106 0
joaopedrodev
joaopedrodev

Einführung

Dieser Artikel ist die Fortsetzung einer Reihe von Artikeln, in denen wir eine Bibliothek namens Connexus aufbauen werden. Im ersten Artikel haben wir die grundlegende Funktionsweise der Funktion WebRequest verstanden, jeden ihrer Parameter kennengelernt und auch einen Beispielcode erstellt, der die Verwendung dieser Funktion und ihre Schwierigkeiten demonstriert. In diesem Artikel werden wir die Bedeutung und Nützlichkeit von Headern in der HTTP-Kommunikation untersuchen und wie diese Elemente für verschiedene Zwecke im modernen Web verwendet werden.

Die Struktur einer HTTP-Nachricht, sei es eine Antwort oder eine Anfrage, besteht aus zwei grundlegenden Elementen, auf die wir näher eingehen werden: Header und Body (Kopf und Hauptteil). Jeder von ihnen hat seine Rolle im Kommunikationsprozess und sorgt dafür, dass die Daten auf organisierte, effiziente und sichere Weise übertragen werden.

Lassen Sie uns zunächst kurz rekapitulieren, wie eine HTTP-Anfrage- und Antwortstruktur funktioniert.


Aufbau einer HTTP-Anfrage

Eine HTTP-Anfrage hat normalerweise dieses Format:

HTTP Method | URL | HTTP Version
Headers
Body (Optional)
  • HTTP-Methode: Definiert den Zweck der Anfrage (GET, POST, PUT, DELETE usw.).
  • URL: Identifiziert die angeforderte Ressource. (Wir haben dies im letzten Artikel ausführlicher besprochen)
  • HTTP-Version: Gibt die verwendete Protokollversion an.
  • Headers: Anforderungsmetadaten, wie z. B. Inhaltstyp, Authentifizierung usw.
  • Body: Der Inhalt der Anfrage, normalerweise in Methoden wie POST oder PUT enthalten.


Aufbau einer HTTP-Antwort

Eine HTTP-Antwort hat eine ähnliche Struktur:

HTTP Version | Status Code | Status Message
Headers
Body (Optional)
  • Status Code: Zeigt das Ergebnis an (200 OK, 404 Not Found, 500 Internal Server Error, usw.).
  • Headers: Informationen über den zurückgegebenen Inhalt, wie Größe, Datentyp usw.
  • Body: Der eigentliche Inhalt der Antwort, z. B. der HTML-Code einer Seite oder JSON-Daten. In unserem Fall ist es üblicher, JSON-Daten zu empfangen, aber beachten Sie, dass einige APIs auch HTML zurückgeben können.

Im letzten Artikel haben wir uns eingehender mit dem Format einer URL befasst und dabei jedes Element für sich betrachtet und zu einer vollständigen Adresse zusammengefügt. In diesem Artikel werden wir die Kopfzeile einer HTTP-Anfrage genauer untersuchen. Wozu dient es? Wie nutze ich es? Welche Werte sind möglich, usw.


Überschriften

Zunächst müssen wir verstehen, was Headers bzw. Kopfzeilen sind. Im HTTP-Protokoll ist ein Header ein Satz zusätzlicher Daten, die mit der Anfrage oder Antwort gesendet werden. HTTP-Header sind wesentliche Funktionen in der Client-Server-Kommunikation. Ihr Hauptzweck ist es, Details über die Anfrage zu liefern, die nicht direkt Teil der URL oder des Nachrichtentextes sind. Sie helfen dabei, den Kommunikationsfluss zu steuern und stellen den Kontext bereit, damit der Server die Daten richtig interpretiert und verarbeitet. Diese Header helfen sowohl dem Server als auch dem Client, den Kontext der Anfrage oder Antwort besser zu verstehen, z. B. den Inhaltstyp, die Zwischenspeicherung, die Authentifizierung usw. Mit anderen Worten: Sie dienen als Metadaten, die dem Server mitteilen, wie die Anfrage verarbeitet werden kann, und dem Client, wie die Antwort zu interpretieren ist.

Im Folgenden werden einige der wichtigsten Funktionen der HTTP-Header genannt:

  1. Authentifizierung: Einer der häufigsten Verwendungszwecke von Headern ist die Authentifizierung des Clients, damit der Server weiß, wer die Anfrage sendet und ob er Zugang zu den Informationen hat. Der Authorization-Header sendet beispielsweise ein Token oder einen Berechtigungsnachweis, den der Server empfängt und zur Validierung des Clients vor der Verarbeitung der Anfrage verwenden kann.
  2. Cache Control: Header wie Cache Control ermöglichen es dem Client und dem Server zu konfigurieren, wie Daten zwischengespeichert werden können, was nützlich sein kann, um eine weitere unnötige Anfrage des Clients an den Server oder des Servers an einen anderen Dienst zu vermeiden. Zwischengespeicherte Daten können auf dem Client, in Proxies oder an anderen Zwischenstationen gespeichert werden.
  3. Spezifikation des Inhalts-Typs: Mit dem Content-Type-Header kann der Client dem Server mitteilen, welche Art von Daten gesendet oder empfangen wird. Üblicherweise werden Formate wie JSON , XML oder HTML verwendet. Dadurch wird sichergestellt, dass beide Seiten der Kommunikation wissen, wie die Daten richtig zu interpretieren sind.
  4. Inhaltliche Verhandlung: Mit dem Accept-Header kann der Client dem Server mitteilen, welche Antwortformate zulässig sind, z. B. application/json (der Server sendet Daten im json-Format) oder text/html (der Server sendet sie im html-Format). Dies ermöglicht es dem Server, die Antwort in einem Format zu senden, das der Client zu empfangen bereit ist. Das am häufigsten verwendete Format ist JSON, auf das wir uns hier konzentrieren werden, aber es werden auch andere Formate unterstützt.
  5. Sicherheit: Header wie Strict-Transport-Security tragen dazu bei, die Verwendung von HTTPS zu verstärken (HTTPS ist dasselbe wie HTTP, enthält aber eine zusätzliche Ebene der Websicherheit. Request, Response, die Headers, der Body, die URL und andere Formate sind genau die gleichen, weshalb empfohlen wird, immer HTTPS zu verwenden.) Andere Header wie CORS (Cross Origin Resource Sharing) legen fest, welche Domänen auf die Ressourcen einer API zugreifen können, was die Sicherheit erhöht. Auf diese Weise filtert der Server, an wen er die Informationen sendet, und sendet sie nur an eine vorher festgelegte Domäne, sodass niemand anderes als diese Domäne auf die Daten zugreifen kann.
  6. Rate Limiting: Einige Dienste geben Header wie X-RateLimit-Limit und X-RateLimit-Reaming zurück, um dem Client mitzuteilen, wie viele Anfragen in einer bestimmten Zeitspanne zulässig sind. Dadurch wird verhindert, dass der Server durch eine große Anzahl von Anfragen überlastet wird.

Daher spielen Header eine entscheidende Rolle bei der HTTP-Kommunikation, da sie Kontrolle, Klarheit und Sicherheit darüber bieten, wie die Anfrage und die Antwort behandelt werden sollen.


Einige mögliche Werte kennen

Schauen wir uns die möglichen Werte der gängigsten Header an. HTTP-Header sind sehr vielseitig und können je nach Bedarf für die Kommunikation zwischen dem Client und dem Server angepasst werden. Verstehen Sie, dass die Werte, die ein Header enthalten kann, vom Kontext der Kommunikation abhängen. Nachstehend finden Sie einige Beispiele für die gängigsten Header und ihre möglichen Werte:

  1. Authorization: Es wird verwendet, um Anmeldeinformationen oder Authentifizierungs-Token vom Client zum Server zu senden und so den Zugriff auf geschützte Ressourcen zu ermöglichen. Sie kann je nach der verwendeten Authentifizierungsmethode unterschiedliche Werte annehmen. Es gibt verschiedene Authentifizierungsmethoden, von denen wir uns die am häufigsten verwendeten ansehen wollen:
    • Bearer Token: Eines der gebräuchlichsten Formate, insbesondere in modernen APIs, die eine tokenbasierte Authentifizierung verwenden. Dieser Wert ist in der Regel ein JWT-Token (JSON Web Token), das der Client nach der Anmeldung oder Authentifizierung bei einem Authentifizierungsserver erhält.

      Authorization: Bearer <my_token_jwt>

      Der Wert <my_token_jwt> ist das Authentifizierungs-Token selbst, in der Regel eine lange Zeichenfolge aus Base64-kodierten Zeichen. Dieses Token enthält Nutzerautorisierungsinformationen und hat eine begrenzte Gültigkeit.

    • Basic: Dieser Wert verwendet die HTTP-Basisauthentifizierung, bei der der Nutzername und das Kennwort Base64-kodiert sind und direkt in der Kopfzeile gesendet werden. Diese Methode ist weniger sicher, da die Anmeldedaten leicht entschlüsselt werden können, und sollte nicht ohne HTTPS verwendet werden.

      Authorization: Basic base64(username:password)

      Der Wert base64(username:password) ist die Base64-Kodierung des Paares Nutzername:Passwort. Obwohl diese Methode einfach ist, ist sie anfällig für Angriffe, wenn sie nicht über verschlüsselte Verbindungen verwendet wird.

    • Digest: Digest ist eine sicherere Methode als Basic und verwendet einen Hash der Anmeldeinformationen des Nutzers, anstatt die Anmeldeinformationen direkt zu senden. Mit dem Aufkommen von OAuth und JWT ist dies heute zwar weniger verbreitet, aber immer noch in einigen APIs zu finden.

      Authorization: Digest username="admin", realm="example", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", response="6629fae49393a05397450978507c4ef1"

      Hier enthält der Wert mehrere Felder, z. B. den Nutzernamen, die Nonce (eine einmalig verwendete Zahl), den Realm (Bereich der Authentifizierung) und die als Hash verschlüsselte Antwort.

  1. Content-Type: Dieser Header definiert die Art des Inhalts im Body der Anfrage oder Antwort. Schauen wir uns einige der am häufigsten verwendeten möglichen Werte an:
    • application/json: Dies ist der gebräuchlichste Wert beim Umgang mit APIs, da JSON ein leichtgewichtiges und einfach zu lesendes und zu schreibendes Format für die Übertragung von Daten ist. Verwendungsbeispiel:

      Content-Type: application/json

    • application/xml: XML (Extensible Markup Language) war vor JSON weit verbreitet und wird auch heute noch in einigen Altsystemen oder alten APIs verwendet. Die meisten aktuellen APIs unterstützen jedoch das JSON-Format, sodass Sie sich vorerst keine Gedanken über XML machen müssen.

      Content-Type: application/xml

    • multipart/form-data: Dieser Wert wird verwendet, um gemischte Daten zu senden, insbesondere wenn der Kunde Dateien oder Formulardaten hochladen muss. Das ist im Moment nicht unser Thema, aber es ist gut zu wissen, dass diese Möglichkeit besteht.

    • text/html: Wird verwendet, wenn der zu sendende oder zu empfangende Inhalt HTML ist. Dieser Wert wird häufig bei Anfragen und Antworten auf Webseiten verwendet.

      Content-Type: text/html

  1. User-Agent: Dieser Header wird vom Client verwendet, um sich zu identifizieren. Sie enthält in der Regel Daten über die Art des Geräts, des Browsers und des Betriebssystems, von dem die Anfrage stammt. Es gibt keine spezifische Regel für die Werte, die hier verwendet werden, aber es gibt einige Standards:
    • Web-Browser: Der von den Browsern gesendete Wert enthält in der Regel Angaben über den Namen und die Version des Browsers sowie über das Betriebssystem.

      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 oder Anwendungen: Anwendungen können den nutzerdefinierten Wert verwenden, z. B.:

      User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)

      Dadurch weiß der Server, dass die Anfrage von einer bestimmten Anwendung kommt, was die Fehlersuche und Überwachung erleichtert.

  1. Accept: Dies wird vom Client verwendet, um mitzuteilen, welche Inhalte er als Antwort akzeptiert. Die möglichen Werte für diesen Header sind ähnlich wie bei Content-Type, sehen wir uns einige davon an:
    • application/json, application/xml, text/html: Sie kennen diese bereits, wir haben sie in der Sitzung „Content-Type“ gesehen.

    • image/png, image/jpeg, image/webp: Diese Werte werden verwendet, wenn der Client den Empfang eines Bildes erwartet. Zum Beispiel in APIs, die grafische Daten bereitstellen, wie Miniaturansichten oder generierte Charts. Oder einfach Bilder wie der Avatar eines Nutzers, das Logo der Website usw.

      Accept: image/png, image/jpeg

      Hier teilt der Kunde mit, dass er sowohl PNG- als auch JPEG-Bilder akzeptiert.

    • */*: Dieser Wert zeigt an, dass der Client jede Art von Inhalt als Antwort akzeptiert. Das wird verwendet, wenn der Kunde keine Präferenz für ein bestimmtes Format hat oder bereit ist, jede Art von Antwort zu akzeptieren.



Wie organisiert man einen Header?

Nachdem wir nun verstanden haben, wofür Header da sind und welche Werte möglich sind, wollen wir uns ansehen, wie Kopfzeilen organisiert sind. Header bestehen aus einer Reihe von Schlüssel- und Wertepaaren und werden in Anfragen eingefügt. Obwohl einige Header für bestimmte Vorgänge obligatorisch sind, sind die meisten optional und hängen von den Bedürfnissen der Anwendung ab. Beispiel für einen einfachen Header für eine HTTP-Anfrage:

GET /api/resource HTTP/1.1
Host: example.com
Authorization: Bearer token123
Content-Type: application/json
User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)

Wie in diesem Beispiel gezeigt, haben wir 3 Kopfzeilen:

  • Authorization: Stellt unser Zugangstoken „token123“ zur Verfügung
  • Content-Type: Liefert Informationen darüber, wie die Daten gesendet werden, wir verwenden JSON
  • User-Agent: Stellt dem Server Informationen zur Verfügung, damit dieser weiß, wie er die Anfrage bearbeiten soll. In diesem Beispiel verwenden wir „Connexus/1.0 (MetaTrader 5 Terminal)“.

Diese Kopfzeilen liefern Informationen, damit der Server weiß, wie die Anfrage zu bearbeiten ist. Dies ist nur ein einfaches Beispiel, und wir werden in Kürze genauer darauf eingehen, welche Sets am häufigsten verwendet werden, welche Werte möglich sind und wofür die einzelnen Sets gedacht sind.


Kommen wir zum Code

Wir haben bereits verstanden, wie Kopfzeilen funktionieren, wozu sie da sind und wie man sie verwendet, jetzt kommen wir zum praktischen Teil. Erinnern Sie sich an httpbin? Es ist ein kostenloser Dienst, der einfach als Spiegel fungiert. Alles, was wir senden, kommt zu uns zurück, und wir überprüfen damit, welche Header wir senden und ob es irgendwelche Header gibt, die das Terminal selbst automatisch hinzufügt. Zu diesem Zweck erstelle wir eine Datei namens TestHeader.mq5 im Ordner Experts/Connexus/Test/TestHeader.mq5. Erstellen wir eine POST-Anfrage, ohne irgendetwas in der Kopfzeile zu senden, und sehen wir uns an, was sie uns antwortet:

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

Wenn wir diesen Code im Terminal ausführen, erhalten wir diese Antwort:

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"
}

Beachten Sie den Wert von „headers“, er enthält ein weiteres json-Objekt mit einigen Header-Werten, die automatisch vom Terminal definiert werden. Denken Sie daran, dass wir in der Anfrage keine Daten senden, weder in der Kopfzeile noch im Textkörper. Wir wollen nun die einzelnen Kopfzeilen verstehen, die automatisch gesendet werden:

  • Accept: Wie wir bereits gesehen haben, teilt er dem Server mit, welche Arten von Inhalten der Client als Antwort akzeptieren möchte. In diesem Fall bedeutet der Wert */* wie zuvor gesehen, dass der Client jede Art von Inhalt als Antwort akzeptiert.

  • Accept-Encoding: gibt die Arten der Inhaltskodierung an, die der Client akzeptieren kann. Kodierungen werden zur Komprimierung von Daten verwendet, um Bandbreite im Netz zu sparen.

    • gzip: Dies ist ein Komprimierungsformat, mit dem die Größe der gesendeten Antwort reduziert werden kann.
    • deflate: Es ist eine weitere Form der Datenkomprimierung, die gzip ähnlich ist, aber einige technische Unterschiede im Algorithmus aufweist.
  • Accept-Language: Dieser Header teilt dem Server mit, welche Sprachen der Client bevorzugt, aber der Server muss mehrere Sprachen unterstützen. Sie hilft dem Server, Inhalte in der für den Nutzer am besten geeigneten Sprache bereitzustellen.

    • pt: Der Kunde zieht es vor, die Antwort in Portugiesisch zu erhalten.
    • de;q=0,5: Hier steht en für Englisch, und q=0,5 wäre ein „Qualitätsfaktor“ (von 0 bis 1), der die relative Priorität der Sprache angibt. Ein Wert von q=1,0 wäre die maximale Präferenz, während q=0,5 bedeutet, dass der Kunde zwar Englisch akzeptiert, aber Portugiesisch bevorzugt.
  • Content-Length: gibt die Body-Größe der Anfrage in Bytes an. In diesem Fall ist der Wert 0, was bedeutet, dass es keinen Inhalt gibt, wie gesagt, wir senden keine Daten im Body der Anfrage.

  • Content-Type: Informiert den Server über die Art der Daten, die an den Server gesendet werden. In diesem Fall bedeutet der Wert application/x-www-form-urlencoded, dass die Daten im URL-kodierten Format gesendet wurden. Ich bin mir nicht sicher, warum MetaTrader 5 dieses Format standardmäßig einstellt.

  • Host: gibt den Namen des Servers an, an den die Anfrage gesendet wird. Dies ist notwendig, damit der Server weiß, welche Domäne oder IP-Adresse angefordert wird, insbesondere wenn er mehrere Domänen unter einer einzigen IP-Adresse bedient.

  • User-Agent: ist eine Zeichenfolge, die den HTTP-Client (in diesem Fall MetaTrader 5) identifiziert, der die Anfrage stellt. Sie enthält Einzelheiten über die verwendete Software und das Betriebssystem.

  • X-Amzn-Trace-Id: Der X-Amzn-Trace-Id-Header wird von AWS-Diensten (Amazon Web Services) verwendet, um Anfragen über ihre verteilte Infrastruktur zu verfolgen. Es hilft, Probleme in Anwendungen, die in der Amazon Cloud laufen, zu identifizieren und zu beheben.

    • Root=1-66feb3d9-50de44d019af8b0c1058436b: Dieser Wert stellt eine eindeutige Tracking-ID dar, die zur Identifizierung einer bestimmten Transaktion verwendet werden kann. Sie ist nützlich für die Diagnose und Leistungsüberwachung.
    • Bedeutung: Diese Kennung wird vom AWS-System automatisch zugewiesen und kann verwendet werden, um den Weg einer Anfrage zu verfolgen, während sie verschiedene Services innerhalb der Amazon-Infrastruktur durchläuft.
    • Allgemeine Verwendung: Dieser Header wird intern von den AWS-Diensten verwendet, um Tracking- und Überwachungsinformationen zu sammeln. Das ist besonders in Microservices-Architekturen nützlich, um Engpässe und Latenzprobleme zu diagnostizieren.

    Ich glaube, dass MetaTrader 5 dies automatisch hinzufügt, damit es die Anfragen des Terminals zur Diagnose der Plattform oder zur Behebung eines Fehlers verfolgen kann.

Nachdem wir nun gesehen haben, welche Kopfzeilen der MetaTrader 5 standardmäßig hinzufügt, können wir einige davon ändern. Denken Sie daran, dass Kopfzeilen nicht zwei identische Schlüssel haben können, d. h. Sie können nicht Content-Type: application/json und Content-Type: application/x-www-form-urlencoded verwenden. Wenn wir also den Wert von Content-Type definieren, wird der alte Wert überschrieben. Ändern wir nun einige Daten, indem wir andere Werte für die folgenden Kopfzeilen festlegen:

  • Content-Type: Content-Type: application/json
  • User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)

Fügen wir diese Werte in die Variable „headers_send“ ein, die eine Zeichenkette ist. Denken Sie daran, das „\n“ hinzuzufügen, um die Kopfzeilen voneinander zu trennen. Hier ist der geänderte Code:

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

Bei der Ausführung des Codes erhalten wir dieses Ergebnis:

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"
}

Beachten Sie, dass wir die Werte User-Agent und Content-Type auf die von uns definierten Werte geändert haben. Da wir nun ein einfaches Beispiel für eine Anfrage haben, die einige nutzerdefinierte Kopfzeilen sendet, fügen wir diese Kopfzeilenfunktion zu unserer Bibliothek hinzu. Unser Ziel ist es, eine Klasse zu erstellen, die mit Kopfzeilen arbeitet. Diese Klasse sollte leicht zu bedienen sein, eine einfache und intuitive Schnittstelle haben und in der Lage sein, Kopfzeilen leicht hinzuzufügen, zu entfernen oder zu aktualisieren.


Erstellen der Klasse HttpHeaders

Erstellen wir einen neuen Ordner innerhalb des Connexus-Ordners, der sich in Includes befindet. Dieser neue Ordner wird Headers heißen, und innerhalb dieses neuen Ordners erstellen wir eine neue Datei namens HttpHeaders.mqh. Am Ende wird es so aussehen:

Pfad

Die Datei sollte eine leere Klasse enthalten, ähnlich der folgenden. Ich habe einige Kommentare hinzugefügt:
//+------------------------------------------------------------------+
//|                                                       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)
  {
  }
//+------------------------------------------------------------------+

Zum Speichern dieser Kopfzeilen wird ein json-Objekt verwendet, wobei der json-Schlüssel der Schlüssel der Kopfzeile und der json-Wert der Wert der Kopfzeile ist. Dazu importieren wir die Klasse json und erstellen eine neue Instanz namens m_headers innerhalb der Klasse.

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

Da das json-Objekt nun bereit ist, die Daten zu speichern, besteht der nächste Schritt darin, zu definieren, welche Methoden diese Klasse haben soll. Zu Beginn werden wir die folgenden Methoden erstellen:

  • Add(string key, string value) : Fügt der HTTP-Anfrage eine neue Kopfzeile hinzu oder aktualisiert sie, wenn sie bereits vorhanden ist.
  • Get(string key) : Gibt den Wert einer bestimmten Kopfzeile zurück, deren Name angegeben ist.
  • Remove(string key) : Entfernt eine bestimmte Kopfzeile.
  • Has(string key) : Prüft, ob eine Kopfzeile mit dem angegebenen Schlüssel vorhanden ist.
  • Clear() : Entfernt alle Kopfzeilen aus der Anfrage.
  • Count() : Gibt die Anzahl der Kopfzeilen zurück.

Fügen wir der Klasse diese einfacheren Methoden hinzu:

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

Nachdem wir nun die einfachsten Methoden hinzugefügt haben, fügen wir nun die letzten beiden Methoden hinzu, die das Herzstück der Klasse sind, nämlich:

  • Serialize() : Gibt alle Kopfzeilen als Zeichenkette zurück, die in einer HTTP-Anfrage gesendet werden können.
  • Parse(string headers) : Konvertiert eine Zeichenkette mit Kopfzeilen (normalerweise in einer HTTP-Antwort) in ein Format, das in der Klasse verwendet werden kann.

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


Tests

Zur Durchführung der Klassentests verwende ich dieselbe Datei, die wir zu Beginn des Artikels erstellt haben, TestHeader.mq5. Binden Sie die HttpHeader-Datei ein und erstellen Sie dann eine Instanz der Klasse CHttpHeader, indem Sie die Daten an die Klasse übergeben. Dann verwende ich die Funktion Serialize(), um sie als String zu formatieren.

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

Wenn wir den Code im Terminal ausführen, erhalten wir die gleiche Antwort:

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"
}


Schlussfolgerung

Kurz gesagt, HTTP-Header sind wie die kleinen Notizen, die Sie im Unterricht weitergeben, damit der Server weiß, was er mit Ihrer Anfrage machen soll. Sie können sich authentifizieren, den Inhaltstyp festlegen, Anweisungen zur Zwischenspeicherung geben und vieles mehr. Ohne sie wäre die HTTP-Kommunikation so chaotisch wie der Versuch, einen Kaffee zu bestellen, ohne die Größe, die Menge des Zuckers oder die Art der Milch anzugeben. Derzeit sieht das Klassendiagramm, das wir bisher erstellt haben, wie folgt aus:

Diagramm connexus

Nachdem Sie nun wissen, wie wichtig Kopfzeilen sind, ist es an der Zeit, etwas noch Interessanteres in Angriff zu nehmen: den Textkörper der Anfrage. Im nächsten Artikel werden wir uns mit dem Herzstück der HTTP-Kommunikation befassen - dem eigentlichen Inhalt, den Sie an den Server senden möchten. Schließlich ist es sinnlos, eine Nachricht ohne Inhalt zu verschicken, oder?

Machen Sie sich darauf gefasst, dass im nächsten Kapitel erörtert wird, wie Sie diese Informationen elegant und effektiv im Text verpacken können. Wir sehen uns dort!

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16043

Erstellen eines MQL5 Expert Advisors basierend auf der PIRANHA Strategie unter Verwendung von Bollinger Bändern Erstellen eines MQL5 Expert Advisors basierend auf der PIRANHA Strategie unter Verwendung von Bollinger Bändern
In diesem Artikel erstellen wir einen Expert Advisor (EA) in MQL5, der auf der PIRANHA-Strategie basiert und Bollinger-Bänder zur Verbesserung der Handelseffektivität nutzt. Wir erörtern die Grundprinzipien der Strategie, die kodierte Umsetzung und die Methoden zur Prüfung und Optimierung. Dieses Wissen ermöglicht es Ihnen, den EA in Ihren Handelsszenarien effektiv einzusetzen
Klassische Strategien neu interpretieren (Teil IX): Analyse mehrerer Zeitrahmen (II) Klassische Strategien neu interpretieren (Teil IX): Analyse mehrerer Zeitrahmen (II)
In der heutigen Diskussion untersuchen wir die Strategie der Analyse mehrerer Zeitrahmen, um zu erfahren, in welchem Zeitrahmen unser KI-Modell am besten abschneidet. Unsere Analyse führt uns zu dem Schluss, dass die monatlichen und stündlichen Zeitrahmen Modelle mit relativ niedrigen Fehlerquoten für das EURUSD-Paar ergeben. Wir haben dies zu unserem Vorteil genutzt und einen Handelsalgorithmus entwickelt, der KI-Prognosen auf dem monatlichen Zeitrahmen erstellt und seine Handelsgeschäfte auf dem stündlichen Zeitrahmen ausführt.
Selbstoptimierender Expert Advisor mit MQL5 und Python (Teil V): Tiefe Markov-Modelle Selbstoptimierender Expert Advisor mit MQL5 und Python (Teil V): Tiefe Markov-Modelle
In dieser Diskussion werden wir eine einfache Markov-Kette auf einen RSI-Indikator anwenden, um zu beobachten, wie sich der Preis verhält, nachdem der Indikator wichtige Niveaus durchlaufen hat. Wir kamen zu dem Schluss, dass die stärksten Kauf- und Verkaufssignale für das NZDJPY-Paar entstehen, wenn der RSI im Bereich von 11-20 bzw. 71-80 liegt. Wir werden Ihnen zeigen, wie Sie Ihre Daten manipulieren können, um optimale Handelsstrategien zu erstellen, die direkt aus den vorhandenen Daten gelernt werden. Darüber hinaus wird demonstriert, wie ein tiefes neuronales Netz so trainiert werden kann, dass es lernt, die Übergangsmatrix optimal zu nutzen.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 41): Deep-Q-Networks MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 41): Deep-Q-Networks
Das Deep-Q-Network ist ein Reinforcement-Learning-Algorithmus, der neuronale Netze bei der Projektion des nächsten Q-Wertes und der idealen Aktion während des Trainingsprozesses eines maschinellen Lernmoduls einsetzt. Wir haben bereits einen alternativen Verstärkungslernalgorithmus, Q-Learning, in Betracht gezogen. Dieser Artikel stellt daher ein weiteres Beispiel dafür vor, wie ein mit Reinforcement Learning trainierter MLP in einer nutzerdefinierten Signalklasse verwendet werden kann.