
Der Body im Connexus (Teil 4): Hinzufügen des HTTP-Hauptteils
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. Im letzten Artikel haben wir verstanden, wie eine Anfrage funktioniert, was Header sind und wie man Header verwendet, um eine Anfrage zu stellen, und schließlich haben wir Unterstützung für verschiedene Header in der Bibliothek entwickelt.
Bei der API-Entwicklung umfasst die Kommunikation zwischen Client und Server das Senden wichtiger Informationen über eine HTTP-Anfrage. Und wenn die Kopfzeilen wie der Umschlag dieser Mitteilung sind, ist der Textkörper der eigentliche Brief, der die eigentlichen Daten enthält, die Sie übermitteln wollen. Im heutigen Artikel werden wir die Rolle des Bodys in einer HTTP-Anfrage, seine Bedeutung und die richtige Konfiguration mit Connexus untersuchen. Fangen wir an!
Was ist der „body“ in HTTP?
Im HTTP-Protokoll bezieht sich der Body einer Anfrage oder Antwort auf den eigentlichen Inhalt, der gesendet oder empfangen wird. Einfach ausgedrückt: Im Body werden die Daten gespeichert, die uns interessieren und die wir an den Server senden oder vom Server empfangen wollen. Es ist der Hauptbestandteil von Anfragen des Typs POST, PUT und PATH, bei denen es notwendig ist, Informationen wie Formulare, strukturierte Daten in Formaten wie JSON oder XML und sogar eine Datei zu senden. In dieser Artikelserie liegt der Schwerpunkt auf der Verwendung des JSON-Formats, das am häufigsten für den Konsum von APIs verwendet wird, aber wir wissen, dass wir auch andere Formate senden können.
Bei einer Anfrage vom Typ GET gibt es in der Regel keinen Body, da diese Art von Anfrage dazu dient, Daten abzufragen, d. h. Informationen zu empfangen und nicht zu senden. Normalerweise antwortet der Server auf diese Art von Anfrage mit einem Body, der die angeforderten Ergebnisse enthält. Bei einer POST-Anfrage ist der Textkörper jedoch von entscheidender Bedeutung, denn über ihn werden die Daten zur Verarbeitung an den Server gesendet. Der Server kann auf diese Art von Anfrage mit einem anderen Body antworten, muss es aber nicht.
Der HTTP-Body dient der Übermittlung von Informationen vom Client zum Server oder umgekehrt, je nach Art der Anfrage. Sie ist unerlässlich für Vorgänge, bei denen Daten erstellt, aktualisiert oder sogar gelöscht werden. Die Hauptfunktion des Body besteht also darin, den „eigentlichen Inhalt“ zu transportieren, den der Server verarbeiten muss. Ohne ihn ist die HTTP-Kommunikation beendet! Konvertieren wir es nun einfach in ein char-Array: Die Kommunikation würde sich auf reine Informationsanfragen beschränken, ohne die Möglichkeit, komplexe Daten zu übermitteln oder anspruchsvollere Aktionen durchzuführen.
Nachdem wir nun die Rolle des Bodys in der HTTP-Kommunikation verstanden haben, ist es wichtig zu wissen, wie man ihn in Anfragen richtig verwendet. Je nach Art der zu übermittelnden Daten kann der Body unterschiedliche Formate haben, z. B. JSON, XML oder Binärdaten (z. B. beim Hochladen von Dateien). Schauen wir uns einige praktische Beispiele an.
-
JSON-Body: Das JSON-Format (JavaScript Object Notation) ist in modernen Anwendungen, insbesondere in REST-APIs, am weitesten verbreitet. Es ist leichtgewichtig, einfach zu lesen und ideal für den Transport strukturierter Daten. Es wird das am häufigsten verwendete Format bei der Verwendung von HTTP in MQL5 sein. Sehen wir uns an, wie JSON in einem Anfragetext verwendet werden kann:
{ "type": "BUY", "symbol": "EURUSD", "price": 1.09223 "volume": 0.01 "tp": 1.09233 "sl": 1.09213 }
In diesem Beispiel senden wir Transaktionsdaten an den Server, sodass der Server die Daten empfangen und verarbeiten, in einer Datenbank speichern und ein Dashboard mit Leistungsmetriken für die Kontotransaktionen erstellen kann, oder er kann die Transaktionsdaten einfach an andere Konten weiterleiten und so ein Transaktionskopiersystem erstellen. Um diesen Body zu verwenden, müssen Sie in der Kopfzeile angeben, dass der Inhaltstyp JSON ist:
Content-Type: application/json
-
Body-Text: Eine weitere gängige Methode, Daten in einer HTTP-Anfrage zu senden, ist das reine Textformat. Dieses Format ist aufgrund seiner Einfachheit von Vorteil. Sie müssen nur schreiben, was Sie senden wollen, ohne viele Regeln oder Konventionen zu befolgen, solange der Server unterstützt, was gesendet wird. Es wird nicht empfohlen, Daten zu versenden, da es schwierig ist, eine große Menge an Daten zu organisieren. Für dieses Szenario empfiehlt sich das Format JSON. Schauen wir uns ein Beispiel für einfachen Text an:
This is a plain text example
Hier werden die Formularfelder aneinandergereiht und durch & getrennt, und jedem Wert wird ein bestimmter Schlüssel zugewiesen. Um dieses Format zu verwenden, sollte die Kopfzeile auf gesetzt werden:
Content-Type: application/text-plain
Dies ist eines der ältesten Formate, aber es wird immer noch in verschiedenen Anwendungen verwendet. Unsere Connexus-Bibliothek wird diesen Inhaltstyp unterstützen, sodass die Entwickler den Ansatz wählen können, der am besten zu ihren Anwendungsfällen passt.
Hinzufügen eines Bodys zu einer HTTP-Anfrage
Nehmen wir ein praktisches Beispiel, bei dem wir ein JSON im Body einer Anfrage senden und prüfen, ob der Server es korrekt empfangen hat. Für diese Prüfung werden wir weiterhin httpbin verwenden, das bereits in früheren Artikeln erwähnt wurde. Gleich zu Beginn werde ich eine weitere Datei mit dem Namen TestBody.mq5 im Ordner Experts/Connexus/Test/TestBody.mq5 erstellen und eine einfache Postanforderung hinzufügen, die im letzten Artikel verwendet wurde. Alle in diesem Artikel verwendeten Dateien sind am Ende des Artikels angefügt.
//+------------------------------------------------------------------+ //| TestBody.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include <Connexus/Data/Json.mqh> #include <Connexus/URL/URL.mqh> #include <Connexus/Header/HttpHeader.mqh> //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- URL CURL url; url.Parse("https://httpbin.org"); url.Path("post"); //--- Data to be sent string method = "POST"; char body_send[]; //--- Headers that will be sent separated by "\n" CHttpHeader headers_send; headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)"); headers_send.Add("Content-Type","application/json"); //--- Data that will be received char body_receive[]; string headers_receive; //--- Send request int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive); //--- Show response Print("Respose: ",CharArrayToString(body_receive)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Der Text der Anfrage muss in der Variable body_send enthalten sein, die ein Array vom Typ char ist. Sie fragen sich vielleicht, warum nicht vom Typ string anstelle von char[], wäre string nicht ideal für das Senden von JSON oder Text? Aus verschiedenen Gründen, die mit Flexibilität, Leistung und Kompatibilität zusammenhängen. Hier sind einige ausführliche Gründe:
- Datentyp-Flexibilität: Der Body einer HTTP-Anfrage kann verschiedene Datentypen enthalten, z. B. Text, JSON, Binärdaten (Dateien, Bilder) oder andere Formate. Die Verwendung eines char-Arrays ermöglicht es der Funktion, jede Art von Daten zu akzeptieren, unabhängig davon, ob sie als Text oder binär dargestellt werden. Enthält der Textkörper eine Datei (Bild, Audio usw.), muss sie als Byte-Array verarbeitet werden, das direkt in einem Char-Array verarbeitet werden kann. Eine Zeichenkette wäre nur für rein textuelle Daten nützlich, was die Verwendung der Funktion auf Szenarien mit binärem Inhalt beschränkt.
- Leistung: Char-Arrays sind effizienter in Bezug auf Low-Level-Datenmanipulation. Da sie den Overhead der dynamischen String-Verwaltung (z. B. Speicherzuweisungen und -neuzuweisungen) nicht mit sich bringen, ermöglichen sie es dem Netzwerkcode, näher an der Hardware zu arbeiten, was für Anwendungen, die eine hohe Leistung erfordern, wie z. B. große Datei-Übertragungen oder Anfragen mit geringer Latenz, unerlässlich ist. Beim Senden einer Anfrage mit einer großen Bilddatei wird durch die Verwendung eines Char-Arrays die Umwandlung des binären Inhalts in eine Zeichenkette vermieden, was CPU-Zyklen spart.
- HTTP-Protokoll-Kompatibilität: Das HTTP-Protokoll arbeitet bei der Übertragung von Daten über Netze direkt mit Bytes. Ein Char-Array (eine Folge von Bytes) spiegelt dieses Low-Level-Verhalten des Protokolls besser wider. Durch die Verwendung von Char-Arrays wird die HTTP-Anforderungsfunktion daher an die Art und Weise angepasst, wie Daten auf Netzebene verarbeitet und übertragen werden.
Die Verwendung eines Char-Arrays für den Body einer HTTP-Anfrage bietet eine höhere Flexibilität, Leistung und Kompatibilität, insbesondere in Szenarien mit binären Daten oder großen Datenmengen. Sie ermöglicht es der Funktion, Daten direkt in ihrer einfachsten Form (Bytes) zu verarbeiten und vermeidet den Overhead und die Einschränkungen der Arbeit mit Strings, die sich besser für Textdaten eignen.
Nun, da wir dies verstanden haben, fügen wir dieser Anfrage einen Textkörper hinzu. Dazu verwenden wir die Funktion StringToCharArray(), die in der Dokumentation beschrieben wird:
Parameter | Typ | Beschreibung |
---|---|---|
text_string | string | Zu kopierende Zeichenfolge. |
array[] | char[] | Array vom Typ uchar. |
start | int | Position, von der aus der Kopiervorgang beginnt. Standardwert - 0. |
count | int | Anzahl der zu kopierenden Array-Elemente. Bestimmt die Länge einer resultierenden Zeichenkette. Der Standardwert ist -1, was bedeutet, dass bis zum Ende des Arrays oder bis zum Terminal 0 kopiert wird. Terminal 0 wird ebenfalls in das Empfänger-Array kopiert. In diesem Fall kann die Größe eines dynamischen Arrays bei Bedarf auf die Größe der Zeichenkette erhöht werden. Wenn die Größe des dynamischen Arrays die Länge der Zeichenkette überschreitet, wird die Größe des Arrays nicht verringert. |
Codepage | uint | Der Wert der Codepage. Bei der Konvertierung von String-Variablen in Arrays vom Typ char und umgekehrt wird in MQL5 die Kodierung verwendet, die standardmäßig dem aktuellen ANSI des Windows-Betriebssystems (CP_ACP) entspricht. Wenn Sie eine andere Art der Kodierung angeben möchten, können Sie diese in diesem Parameter festlegen. |
In der folgenden Tabelle sind die internen Konstanten einiger der beliebtesten Codepages aufgeführt. Nicht spezifizierte Codepages können über die entsprechende Codepage angegeben werden.
Konstante | Wert | Beschreibung |
---|---|---|
CP_ACP | 0 | Die aktuelle Windows ANSI-Codepage. |
CP_OEMCP | 1 | Die aktuelle System-OEM-Code-Seite. |
CP_MACCP | 2 | Die aktuelle Macintosh-Codepage des Systems. Dieser Wert wird vor allem in früher erstellten Programmcodes verwendet und hat heute keine Bedeutung mehr, da moderne Macintosh-Computer Unicode zur Kodierung verwenden. |
CP_THREAD_ACP | 3 | Die Windows ANSI-Codepage für den aktuellen Thread. |
CP_SYMBOL | 42 | Symbol-Code-Seite |
CP_UTF7 | 65000 | UTF-7-Codepage. |
CP_UTF8 | 65001 | UTF-8-Codepage. |
Für die meisten APIs werden wir UTF8 verwenden, eine Standardkodierung für E-Mails, Webseiten und andere. Fügen wir also einen Body im json-Format mit UTF8-Kodierung hinzu:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Data to be sent string method = "POST"; CJson body; body["type"] = "BUY"; body["symbol"] = "EURUSD"; body["price"] = 1.09223; body["volume"] = 0.01; body["tp"] = 1.09233; body["sl"] = 1.09213; //--- {"price": 1.09223,"sl": 1.09213,"symbol": "EURUSD","tp": 1.09233,"type": "BUY","volume": 0.01} //--- Char that will be sent char body_send[]; //--- Convert string to char (UTF8) StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8); //--- Show char array ArrayPrint(body_send); return(INIT_SUCCEEDED); }
Wenn Sie diesen Code ausführen, wird er in der Toolbox angezeigt:
Beachten Sie, dass an der letzten Position des Arrays der Wert „0“ steht, was für den Server ein Problem darstellen kann, wenn er den Request Body liest. Um dies zu vermeiden, entfernen wir die letzte Position des Arrays mit den Funktionen ArrayRemove() und ArraySize().
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Data to be sent string method = "POST"; CJson body; body["type"] = "BUY"; body["symbol"] = "EURUSD"; body["price"] = 1.09223; body["volume"] = 0.01; body["tp"] = 1.09233; body["sl"] = 1.09213; //--- {"price": 1.09223,"sl": 1.09213,"symbol": "EURUSD","tp": 1.09233,"type": "BUY","volume": 0.01} //--- Char that will be sent char body_send[]; //--- Convert string to char (UTF8) StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8); ArrayRemove(body_send,ArraySize(body_send)-1); //--- Show char array ArrayPrint(body_send); return(INIT_SUCCEEDED); }
Wenn Sie es erneut ausführen, wird dies in der Toolbox angezeigt:
Nun, da wir diese kleine Änderung erledigt haben, fügen wir diesen Body zu einer http-Anfrage hinzu:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- URL CURL url; url.Parse("https://httpbin.org"); url.Path("post"); //--- Data to be sent string method = "POST"; CJson body; body["type"] = "BUY"; body["symbol"] = "EURUSD"; body["price"] = 1.09223; body["volume"] = 0.01; body["tp"] = 1.09233; body["sl"] = 1.09213; char body_send[]; StringToCharArray(body.Serialize(),body_send,0,WHOLE_ARRAY,CP_UTF8); ArrayRemove(body_send,ArraySize(body_send)-1); //--- Headers that will be sent separated by "\n" CHttpHeader headers_send; headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)"); headers_send.Add("Content-Type","application/json"); //--- Data that will be received char body_receive[]; string headers_receive; //--- Send request int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive); //--- Show response Print("Respose: ",CharArrayToString(body_receive)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Wenn wir diesen Code ausführen, erhalten wir diese Antwort von httpbin:
Respose: { "args": {}, "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":1.09223000,\"volume\":0.01000000,\"tp\":1.09233000,\"sl\":1.09213000}", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "pt,en;q=0.5", "Content-Length": "103", "Content-Type": "text/plain", "Host": "httpbin.org", "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", "X-Amzn-Trace-Id": "Root=1-67081b9c-3def4b1527d04edc1511cc6b" }, "json": { "price": 1.09223, "sl": 1.09213, "symbol": "EURUSD", "tp": 1.09233, "type": "BUY", "volume": 0.01 }, "origin": "189.74.63.39", "url": "https://httpbin.org/post" }
Beachten Sie zwei interessante Dinge: Das erste ist, dass das Feld „data“ das JSON enthält, das wir im Body im String-Format gesendet haben, was bedeutet, dass der Server die gesendeten Daten empfangen und korrekt interpretieren konnte. Außerdem enthält das Feld „json“ den von uns gesendeten JSON-Code, was wiederum zeigt, dass der Server die Daten korrekt empfangen hat. Funktioniert perfekt!
Erstellen der Klasse CHttpBody
Da wir nun wissen, wie der Body funktioniert, wofür er da ist und wie man ihn verwendet, wollen wir in der Connexus-Bibliothek eine Klasse erstellen, die mit dem Request Body arbeitet. Der Name dieser Klasse wird CHttpBody sein, und sie wird Methoden haben, um mit dem Body zu arbeiten und Daten hinzuzufügen, zu aktualisieren oder zu entfernen. Es wird auch möglich sein, die verwendete Kodierung zu definieren (Standard ist UTF8).
Erstellen wir eine neue Datei namens HttpBody.mqh im Ordner Include/Connexus/Header/HttpBody,mqh. Bei der Erstellung der Datei sieht sie zunächst ähnlich aus wie diese:
//+------------------------------------------------------------------+ //| HttpBody.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpBody | //| | //| [PROPERTY] | //| Name : CHttpBody | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the body of | //| a request. | //| | //+------------------------------------------------------------------+ class CHttpBody { public: CHttpBody(void); ~CHttpBody(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpBody::CHttpBody(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpBody::~CHttpBody(void) { } //+------------------------------------------------------------------+
Definieren wir einige private Eigenschaften der Klasse, sie sind:
- m_body: Speichert den Request Body als char-Array.
- m_codepage: Dient zum Speichern der definierten Kodierung
//+------------------------------------------------------------------+ //| Include the file CJson class | //+------------------------------------------------------------------+ #include "../Data/Json.mqh" //+------------------------------------------------------------------+ //| class : CHttpBody | //| | //| [PROPERTY] | //| Name : CHttpBody | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the body of | //| a request. | //| | //+------------------------------------------------------------------+ class CHttpBody { private: char m_body[]; // Will store the request body as a char array uint m_codepage; // Used to store the defined encoding };; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpBody::CHttpBody(void) { m_codepage = CP_UTF8; } //+------------------------------------------------------------------+
Lassen Sie uns nun einige öffentliche Methoden definieren, um den Body des Requests zu bearbeiten:
- Daten zum Body hinzufügen
- AddString(string data): Fügt eine Textzeichenkette in den Request-Body ein.
- AddJson(CJson data): Fügt dem Text-Body JSON-formatierte Daten hinzu. Dies kann die Umwandlung eines JSON-Objekts in eine formatierte Zeichenkette beinhalten.
- AddBinary(char &data[]): Ermöglicht das direkte Hinzufügen von Binärdaten (z. B. Dateien) zum Anfrage-Body.
- Daten aus dem Körper entfernen
- Clear(void): Entfernt den gesamten Inhalt des Request-Body, sodass wir von vorne beginnen können.
- Den Inhalt des Body abrufen
- GetAsString(void): Gibt den Request-Body als Zeichenkette zurück.
- GetAsJson(void): Konvertiert den Body der Anfrage in ein JSON-Objekt, was nützlich ist, wenn der Body strukturierte Daten enthält. - GetAsChar(char &body[]): Gibt den Body als Array von Bytes zurück, nützlich für die Arbeit mit Binärdaten.
- Überprüfung der Body-Größe
- GetSize(void): Gibt die Größe des Request-Bodys zurück, normalerweise in Bytes.
- Kodierung
- GetCodePage(void): Gibt die definierte Codepage zurück
- SetCodePage(uint codepage): Legt die zu verwendende Codepage fest
Fügen wir diese Methoden zu den Klassen hinzu, so wird es am Ende so aussehen:
//+------------------------------------------------------------------+ //| class : CHttpBody | //| | //| [PROPERTY] | //| Name : CHttpBody | //| Heritage : No heritage | //| Description : Responsible for organizing and storing the body of | //| a request. | //| | //+------------------------------------------------------------------+ class CHttpBody { private: char m_body[]; // Will store the request body as a char array uint m_codepage; // Used to store the defined encoding public: CHttpBody(void); ~CHttpBody(void); //--- Add data to the body void AddString(string data); // Adds a text string to the request body void AddJson(CJson &data); // Adds data in JSON format to the body void AddBinary(char &data[]); // Allows you to add binary data //--- Clear the body void Clear(void); // Remove all body content //--- Gets the body content string GetAsString(void); // Returns the request body as a string CJson GetAsJson(void); // Converts the request body into a JSON object, useful when the body contains structured data void GetAsBinary(char &body[]); // Returns the body as an array of bytes, useful for working with binary data //--- Size in bytes int GetSize(void); // Returns the size of the request body, usually in bytes //--- Codepage uint GetCodePage(void); // Returns the defined codepage void SetCodePage(uint codepage); // Defines the codepage to be used }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpBody::CHttpBody(void) { m_codepage = CP_UTF8; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpBody::~CHttpBody(void) { } //+------------------------------------------------------------------+ //| Adds a text string to the request body | //+------------------------------------------------------------------+ void CHttpBody::AddString(string data) { StringToCharArray(data,m_body,this.GetSize()-1,WHOLE_ARRAY,m_codepage); ArrayRemove(m_body,this.GetSize()-1); } //+------------------------------------------------------------------+ //| Adds data in JSON format to the body | //+------------------------------------------------------------------+ void CHttpBody::AddJson(CJson &data) { this.AddString(data.Serialize()); } //+------------------------------------------------------------------+ //| Allows you to add binary data | //+------------------------------------------------------------------+ void CHttpBody::AddBinary(char &data[]) { ArrayCopy(m_body,data); } //+------------------------------------------------------------------+ //| Remove all body content | //+------------------------------------------------------------------+ void CHttpBody::Clear(void) { ArrayFree(m_body); } //+------------------------------------------------------------------+ //| Returns the request body as a string | //+------------------------------------------------------------------+ string CHttpBody::GetAsString(void) { return(CharArrayToString(m_body,0,WHOLE_ARRAY,m_codepage)); } //+------------------------------------------------------------------+ //| Converts the request body into a JSON object, useful when the | //| body contains structured data | //+------------------------------------------------------------------+ CJson CHttpBody::GetAsJson(void) { CJson json; json.Deserialize(this.GetAsString()); return(json); } //+------------------------------------------------------------------+ //| Returns the body as an array of bytes, useful for working with | //| binary data | //+------------------------------------------------------------------+ void CHttpBody::GetAsBinary(char &body[]) { ArrayCopy(body,m_body); } //+------------------------------------------------------------------+ //| Returns the size of the request body, usually in bytes | //+------------------------------------------------------------------+ int CHttpBody::GetSize(void) { return(ArraySize(m_body)); } //+------------------------------------------------------------------+ //| Returns the defined codepage | //+------------------------------------------------------------------+ uint CHttpBody::GetCodePage(void) { return(m_codepage); } //+------------------------------------------------------------------+ //| Defines the codepage to be used | //+------------------------------------------------------------------+ void CHttpBody::SetCodePage(uint codepage) { m_codepage = codepage; } //+------------------------------------------------------------------+
Diese Methoden sind einfach und überschaubar - die größte von ihnen ist nur drei Zeilen lang. Lassen Sie sich jedoch nicht von ihrer Einfachheit täuschen. Sie sind äußerst nützlich und haben einen erheblichen Einfluss auf die Reduzierung der Gesamtzahl der Codezeilen in Ihrer Bibliothek. Dadurch wird nicht nur Ihr Code schlanker, sondern Ihre Bibliothek wird auch viel einfacher zu nutzen und zu warten sein.
Tests
Gehen wir nun zu den Tests über und sehen wir uns an, wie sich die Klasse verhält. Ich werde dieselbe Datei wie zu Beginn des Artikels verwenden, TestBody.mq5.
{ "type": "BUY", "symbol": "EURUSD", "price": 1.09223 "volume": 0.01 "tp": 1.09233 "sl": 1.09213 }
In diesem Test fügen wir dieses JSON in den Textkörper einer POST-Anfrage ein. Wir werden das json-Objekt mit den Daten erstellen:
CJson body_json; body_json["type"] = "BUY"; body_json["symbol"] = "EURUSD"; body_json["price"] = 1.09223; body_json["volume"] = 0.01; body_json["tp"] = 1.09233; body_json["sl"] = 1.09213;
Erstellen wir eine Instanz der Klasse CHttpBody und fügen wir dieses JSON darin ein:
CHttpBody body; body.AddJson(body_json);
Erledigt! Konvertieren wir es jetzt einfach in ein char-Array:
//--- Body in char array char body_send[]; body.GetAsBinary(body_send);
So einfach ist es, wir fügen das JSON ohne Komplikationen in die Anfrage ein. Dieser letzte Schritt der Konvertierung in ein char-Array wird am Ende der Bibliothek nicht notwendig sein, da wir uns noch in der Entwicklung befinden und noch alles „von Hand“ machen. Am Ende wird der Code wie folgt aussehen:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- URL CURL url; url.Parse("https://httpbin.org"); url.Path("post"); //--- Data to be sent string method = "POST"; CJson body_json; body_json["type"] = "BUY"; body_json["symbol"] = "EURUSD"; body_json["price"] = 1.09223; body_json["volume"] = 0.01; body_json["tp"] = 1.09233; body_json["sl"] = 1.09213; CHttpBody body; body.AddJson(body_json); //--- Body in char array char body_send[]; body.GetAsBinary(body_send); //--- Headers that will be sent separated by "\n" CHttpHeader headers_send; headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)"); headers_send.Add("Content-Type","application/json"); //--- Data that will be received char body_receive[]; string headers_receive; //--- Send request int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive); //--- Show response Print("Respose: ",CharArrayToString(body_receive)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+Bei der Ausführung erhalten wir dieses Ergebnis:
Respose: { "args": {}, "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":1.09223000,\"volume\":0.01000000,\"tp\":1.09233000,\"sl\":1.09213000}", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "pt,en;q=0.5", "Content-Length": "103", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "Connexus/1.0 (MetaTrader 5 Terminal)", "X-Amzn-Trace-Id": "Root=1-670902d1-5a796b1e1fe2053f18a07654" }, "json": { "price": 1.09223, "sl": 1.09213, "symbol": "EURUSD", "tp": 1.09233, "type": "BUY", "volume": 0.01 }, "origin": "189.74.63.39", "url": "https://httpbin.org/post" }
Beachten Sie noch einmal, dass die Felder „data“ und „json“ ein Objekt enthalten, was bedeutet, dass der Server die Daten, die wir im Body gesendet haben, korrekt empfangen hat. Wenn Sie einen Body mit einfachem Text ohne Formatierung senden möchten, fügen Sie ihn einfach als Zeichenkette in die CHttpBody-Klasse ein und ändern Sie den Header in text/plain, wie wir im letzten Artikel gesehen haben:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- URL CURL url; url.Parse("https://httpbin.org"); url.Path("post"); //--- Data to be sent string method = "POST"; CHttpBody body; body.AddString("My simple text"); //--- Body in char array char body_send[]; body.GetAsBinary(body_send); //--- Headers that will be sent separated by "\n" CHttpHeader headers_send; headers_send.Add("User-Agent","Connexus/1.0 (MetaTrader 5 Terminal)"); headers_send.Add("Content-Type","text/plain"); //--- Data that will be received char body_receive[]; string headers_receive; //--- Send request int status_code = WebRequest(method,url.FullUrl(),headers_send.Serialize(),5000,body_send,body_receive,headers_receive); //--- Show response Print("Respose: ",CharArrayToString(body_receive)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Schlussfolgerung
In diesem Artikel haben wir das Konzept des Body in HTTP-Anfragen untersucht und seine grundlegende Rolle bei der Datenübertragung zwischen Client und Server aufgezeigt. Wir wissen, dass der Body der Ort ist, an dem wir die Daten platzieren, die wir senden wollen, und dass sie auf verschiedene Arten formatiert werden können, z. B. als JSON, XML und sogar als Datei, aber wir haben mehr die Verwendung von JSON untersucht, das im Zusammenhang mit APIs, auf die wir uns jetzt konzentrieren, am häufigsten verwendet wird. Außerdem haben wir die Header besprochen, die für jede Art von Body erforderlich sind, um sicherzustellen, dass die Anfrage vom Server richtig interpretiert wird.
Außerdem haben wir in der Connexus-Bibliothek die Klasse CHttpBody eingeführt, die für die Arbeit mit dem Body der Anfrage zuständig ist. Diese Klasse ermöglicht eine einfache Manipulation der zu sendenden Daten, ohne sich um die Formatierung auf niedriger Ebene (Bytes) zu kümmern.
Im nächsten Artikel dieser Reihe werden wir noch tiefer in die Vorgänge des HTTP-Protokolls eindringen und einige Methoden wie GET, POST, PUT, DELETE und andere untersuchen. Wir werden auch HTTP-Statuscodes besprechen, wie 200 (Ok), vielleicht der bekannteste im Web, 404 (Not Found) und andere wie 500 (Internal Server Error), und was sie für die Kommunikation zwischen Client und Server bedeuten. Bleiben Sie dran!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16098





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.