English Русский 日本語
preview
HTTP und Connexus (Teil 2): Verstehen der HTTP-Architektur und des Bibliotheksdesigns

HTTP und Connexus (Teil 2): Verstehen der HTTP-Architektur und des Bibliotheksdesigns

MetaTrader 5Beispiele | 27 November 2024, 09:49
94 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 etwas mehr über das HTTP-Protokoll erfahren, wie eine URL funktioniert und welche Elemente verwendet werden, um eine URL zu erstellen, und wir werden zwei erste Klassen erstellen, nämlich

  • CQueryParam: Klasse zur Verwaltung von Abfrageparametern in der URL
  • CURL: Klasse, die alle Elemente einer URL enthält, einschließlich einer Instanz von CQueryParam


Was ist HTTP?

HTTP ist ein Kommunikationsprotokoll, das für die Datenübertragung im Internet verwendet wird. Es basiert auf dem TCP/IP-Protokoll, das die Verbindung zwischen dem Client und dem Server herstellt. HTTP ist ein zustandsloses Protokoll, was bedeutet, dass jede Anfrage unabhängig ist, ohne Kenntnis der vorherigen Anfragen. Eine HTTP-Anfrage und -Antwort besteht aus drei Hauptbestandteilen:

1. Request Zeile

Die Anforderungszeile (request) enthält drei Elemente:

  • HTTP-Methode: Legt die auszuführende Aktion fest (GET, POST, PUT, DELETE, usw.).
  • URL: Gibt die angeforderte Ressource an.
  • HTTP-Version: Gibt die verwendete Protokollversion an (HTTP/1.1, HTTP/2 usw.).

Beispiel für Anfrage (REQUEST) und Antwort (RESPONSE):

REQUEST
GET /index.html HTTP/1.1

RESPONSE
HTTP/1.1 200 OK

2. Request Headers

Kopfzeilen (headers) liefern zusätzliche Informationen über die Anfrage, wie z. B. den Inhaltstyp, den Nutzeragenten (Browser) und die Authentifizierung. Beispiel:

Host: www.exemplo.com
User-Agent: Mozilla/5.0
Accept-Language: en-US,en;q=0.5

3. Request Body

Nicht alle Anfragen haben einen Hauptteil, den „body“, aber bei Methoden wie POST und PUT, bei denen Daten (z. B. Formulare oder Dateien) an den Server gesendet werden, ist er üblich.


Allgemeine HTTP-Methoden

HTTP-Methoden sind wichtig, um die Art der Aktion zu bestimmen, die vom Client beim Server angefordert wird. Jede Methode hat einen bestimmten Zweck, z. B. das Abrufen von Daten, das Senden von Informationen oder das Ändern einer Ressource. Lassen Sie uns einen tieferen Einblick in die gängigsten HTTP-Methoden, ihre Verwendungszwecke und bewährte Verfahren nehmen.

  • GET: Die GET-Methode ist die am weitesten verbreitete Methode des HTTP-Protokolls. Sie wird verwendet, um Daten von einem Server abzurufen oder zu suchen, ohne dessen Zustand zu verändern. Das Hauptmerkmal von GET ist, dass es idempotent ist, d. h. mehrere GET-Anfragen für dieselbe Ressource ändern den Zustand der Anwendung nicht.
    • Eigenschaften
      • Keine Seiteneffekte: Nur Daten lesen. Auf dem Server sollte sich nichts ändern.
      • Leerer Hauptteil: Im Allgemeinen enthält eine GET-Anfrage keinen Hauptteil (body).
      • Cachefähig: GET-Antworten können vom Browser zwischengespeichert werden, um die Leistung zu verbessern.
    • Wann ist sie zu verwenden?
      • Zum Holen statischer Daten wie HTML-Seiten, Bilder, Dateien oder Informationen in einem Format wie JSON.
      • Zum Abrufen von Informationen aus einer Datenbank, ohne die Daten zu verändern.
  • POST: Die POST-Methode wird verwendet, um Daten an den Server zu senden, normalerweise um neue Ressourcen zu erstellen. Im Gegensatz zu GET wird hier der Zustand des Servers geändert. POST ist nicht idempotent, d. h., wenn Sie dieselbe Anfrage mehrmals senden, können Sie mehrere Ressourcen erstellen.
    • Eigenschaften
      • Ändert den Zustand des Servers: Wird in der Regel zur Erstellung neuer Ressourcen verwendet.
      • Antrag auf Einrichtung vorhanden: Enthält die Daten, die an den Server gesendet werden sollen.
      • Nicht cachefähig: Im Allgemeinen sollten POST-Anfragen nicht zwischengespeichert werden.
    • Wann ist sie zu verwenden?
      • Zum Übersenden von Formularen mit Daten.
      • Zum Erstellen neuer Ressourcen, z. B. indem ein neues Element zu einer Datenbank hinzugefügt wird.
  • PUT: Die PUT-Methode wird verwendet, um eine Ressource auf dem Server zu aktualisieren. Wenn die Ressource noch nicht vorhanden ist, kann sie mit PUT erstellt werden. Das Hauptmerkmal von PUT ist, dass es idempotent ist: mehrere PUT-Anfragen mit demselben Anfragerumpf führen immer zum selben Ergebnis.
    • Eigenschaften
      • Idempotent: Wiederholte Anfragen mit demselben Text haben die gleiche Wirkung.
      • Vollständige Ressource gesendet: Der Hauptteil der Anfrage (body) enthält in der Regel eine vollständige Darstellung der zu aktualisierenden Ressource.
      • Kann erstellen oder aktualisieren: Wenn die Ressource nicht existiert, kann PUT sie erstellen.
    • Wann ist sie zu verwenden?
      • Um eine bestehende Ressource vollständig zu aktualisieren oder zu ersetzen.
      • Zum Erstellen einer Ressource, wenn sie nicht existiert, über eine bestimmte URL.
  • DELETE: Die DELETE-Methode wird verwendet, um eine bestimmte Ressource vom Server zu entfernen. Wie PUT ist auch DELETE idempotent, d. h., wenn Sie mehrere DELETE-Anfragen für dieselbe Ressource stellen, ist das Ergebnis dasselbe: Die Ressource wird entfernt (oder bleibt verschwunden, wenn sie bereits gelöscht wurde).
    • Eigenschaften
      • Idempotent: Wenn eine Ressource gelöscht werden soll, die bereits gelöscht wurde, gibt der Server einen Erfolg zurück.
      • Keinen Hauptteil (body): Normalerweise hat die Anfrage DELETE keinen Body.
    • Wann ist sie zu verwenden?
      • Um bestimmte Server-Ressourcen zu entfernen, z. B. das Löschen von Daten aus einer Datenbank.
  • PATCH: Die PATCH-Methode wird für partielle Aktualisierungen einer Ressource verwendet. Im Gegensatz zu PUT, wo Sie die vollständige Darstellung der Ressource senden müssen, können Sie mit PATCH nur die Felder ändern, die aktualisiert werden müssen.
  • HEAD: Ähnlich wie GET, jedoch ohne den Hauptteil (body) der Antwort. Dient zur Überprüfung von Informationen über eine Ressource.
  • OPTIONS: Dient zur Beschreibung der Kommunikationsoptionen mit dem Server, einschließlich der unterstützten Methoden.
  • TRACE: Wird für Diagnosen verwendet und gibt zurück, was vom Client an den Server gesendet wurde.


HTTP Statuscodes

HTTP-Statuscodes sind Antworten, die der Server an den Client sendet, um ihn über das Ergebnis einer Anfrage zu informieren. Diese Codes sind numerisch und zeigen an, ob die Anfrage erfolgreich war oder fehlgeschlagen ist, sowie Fehler oder Weiterleitungen. Sie sind in fünf Hauptkategorien unterteilt, die jeweils einen bestimmten Zahlenbereich aufweisen und eine klare und detaillierte Rückmeldung über den Verlauf der Bearbeitung der Anfrage geben.

Im Folgenden werden die einzelnen Kategorien und einige der am häufigsten verwendeten Codes näher erläutert.

1xx: Informative Antworten: Statuscodes der Reihe 1xx zeigen an, dass der Server die Anfrage erhalten hat und dass der Client auf weitere Informationen warten sollte. Diese Antworten werden in der täglichen Praxis selten verwendet, können aber in bestimmten Szenarien wichtig sein.

2xx: Erfolg: Statuscodes der Reihe **2xx** zeigen an, dass die Anfrage **erfolgreich** war. Dies sind die Codes, die wir in den meisten Fällen sehen wollen, da sie anzeigen, dass die Interaktion zwischen Client und Server wie erwartet verlaufen ist.

3xx: Umgeleitet: Codes der Reihe 3xx zeigen an, dass der Client eine zusätzliche Aktion durchführen muss, um die Anfrage abzuschließen, in der Regel eine Umleitung zu einer anderen URL.

4xx: Client-Fehler: Codes der Reihe 4xx zeigen an, dass bei der Anfrage des Clients ein Fehler aufgetreten ist. Diese Fehler können durch ein falsches Datenformat, fehlende Authentifizierung oder Zugriffsversuche auf nicht existierende Ressourcen verursacht werden.

5xx: Server-Fehler: Codes der Reihe 5xx zeigen an, dass bei der Bearbeitung der Anfrage ein interner Fehler auf dem Server aufgetreten ist. Bei diesen Fehlern handelt es sich in der Regel um Backend-Probleme, wie z. B. interne Dienstausfälle, Konfigurationsfehler oder Systemüberlastung.


Erstellen einer URL

Eine URL (Uniform Resource Locator) ist die Art und Weise, wie wir Ressourcen im Web identifizieren und darauf zugreifen. Sie besteht aus mehreren Elementen, die wichtige Informationen liefern, wie z. B. den Serverstandort, die angeforderte Ressource und optional zusätzliche Parameter, die zum Filtern oder Anpassen von Antworten verwendet werden können.

Im Folgenden werden die einzelnen Komponenten einer URL und die Verwendung von Abfrageparametern zur Übermittlung zusätzlicher Informationen in einer HTTP-Anfrage näher erläutert.

URL-Struktur

Eine typische URL hat dieses Format:

protocol://domain:port/path?query=params#fragment

Jedes Teil hat eine bestimmte Aufgabe:

  1. Protocol: Gibt an, welches Protokoll für die Kommunikation verwendet wird, z. B. http oder https . Beispiel: https://.
  2. Domain: Name des Servers, auf dem die Ressource gehostet wird. Dies kann ein Domänenname (z. B. example.com ) oder eine IP-Adresse (z. B. 192.168.1.1 ) sein.
  3. Port: Optionale Zahl, die den Server-Port angibt, der für die Kommunikation verwendet werden soll. Wird diese Option nicht angegeben, verwendet der Browser die Standardports, z. B. 80 für http und 443 für https. Beispiel: :8080 .
  4. Path: Gibt die Ressource oder Route auf dem Server an. Dies können Seiten, API-Endpunkte oder Dateien sein. Beispiel: /api/v1/users .
  5. Query Params: Wird verwendet, um zusätzliche Informationen an den Server zu übermitteln. Sie folgen auf das Fragezeichen ( ? ) und werden aus Schlüssel-Wert-Paaren gebildet. Mehrere Parameter werden durch & getrennt. Beispiel: ?name=John&age=30 .
  6. Fragment: Bezeichnet einen bestimmten Teil der Ressource, z. B. einen Ankerpunkt innerhalb einer HTML-Seite. Folgt auf das Rautenzeichen ( # ). Beispiel: #section2 . Normalerweise sind Fragmente weder nützlich noch werden sie verwendet, um Daten von APIs zu konsumieren. Dies liegt daran, dass Fragmente ausschließlich auf der Client-Seite verarbeitet werden, d. h. vom Browser oder von der Schnittstelle der Anwendung, die die Webseite konsumiert. Der Server empfängt das URL-Fragment nicht und kann es daher nicht in HTTP-Anforderungen verwenden, die an den Server gesendet werden, z. B. wenn eine API genutzt wird. Aus diesem Grund wird unsere Bibliothek keine Fragmente unterstützen.


Vollständiges Beispiel

Analysieren wir die folgende URL:

https://www.exemplo.com:8080/market/symbols?active=EURUSD&timeframe=h1

Hier haben wir:

  • Protocol: https
  • Domain: www.example.com
  • Port: 8080
  • Path: /market/symbols
  • Query Params: active=EURUSD&timeframe=h1


Praktische Anwendung: Beginnen wir die Connexus-Bibliothek zu erstellen

Um mit dem Aufbau der Connexus-Bibliothek zu beginnen, werden wir uns auf die Klassen konzentrieren, die für die Erstellung und Bearbeitung von URLs und Abfrageparametern verantwortlich sind. Wir werden ein Modul erstellen, das bei der Erstellung von URLs und dem Hinzufügen von Abfrageparametern dynamisch und programmatisch hilft.


Struktur der Klasse

Wir beginnen mit der Erstellung einer CURL-Klasse, die für die Erstellung und Bearbeitung von URLs zuständig ist. Es ermöglicht dem Nutzer, auf einfache Weise Abfrageparameter hinzuzufügen, die Basis-URL zu erstellen und verschiedene Elemente der URL effizient zu handhaben. Um die Abfrageparameter einer URL organisiert und effizient zu verwalten, verwenden wir eine Klasse namens CJson. Das Ziel dieser Klasse ist es, die Abfrageparameter (die normalerweise als String in der URL übergeben werden) in ein strukturiertes und einfach zu verwaltendes Format zu konvertieren: JSON.


Was ist JSON?

Bevor wir uns mit den Funktionen der Klasse CJson befassen, ist es wichtig, das JSON-Format (JavaScript Object Notation) zu verstehen, falls Sie damit noch nicht vertraut sind. JSON ist ein sehr verbreitetes Datenformat, das im Web zur Darstellung strukturierter Daten verwendet wird. Sie besteht aus Schlüsselpaaren, wobei jedem Schlüssel ein Wert zugeordnet ist. Diese Paare werden durch Kommata getrennt und zwischen geschweiften Klammern „{}“ gruppiert

Beispiel für ein JSON-Objekt:

{
  "name": "John",
  "age": 30,
  "city": "New York"
}

Hier haben wir ein JSON-Objekt, das drei Schlüsselpaare „name“, „age“ und „city“ mit ihren jeweiligen Werten enthält. Bei Abfrageparametern einer URL funktioniert jeder Parameter auf ähnliche Weise: Es gibt einen Schlüssel (Parametername) und einen Wert (der mit diesem Schlüssel verbundene Wert).


Zweck der Klasse CJson

Die Klasse CJson wird verwendet, um die URL-Abfrageparameter in einem JSON-Format zu organisieren. Dadurch wird es einfacher, diese Parameter zu manipulieren, zu lesen und sogar zu validieren, bevor sie in die endgültige URL aufgenommen werden. Anstatt mit einer Reihe von Parametern wie ?name=John&age=30 zu arbeiten, können Sie mit einem strukturierten Objekt arbeiten, was den Code sauberer und verständlicher macht. Die Klasse CJson wird auch für das Senden und Empfangen von Daten nützlich sein, was wir in den nächsten Artikeln sehen werden.


Erstellen der ersten Klassen

Wir beginnen mit der Erstellung eines Ordners namens Connexus im Verzeichnis „Include“ im Metaeditor. Wir erstellen innerhalb des Connexus-Ordners einen weiteren Ordner mit dem Namen URL und einen weiteren mit dem Namen Data. Innerhalb des URL-Ordners erstellen wir eine Datei mit dem Namen URL und QueryParam, und ich werde dem Artikel auch die CJson-Klasse beifügen, die dem Data-Ordner hinzugefügt werden sollte. Ich werde nicht näher auf die Implementierung dieser Klasse eingehen, aber sie ist einfach zu nutzen, glauben Sie mir. Die Struktur sollte in etwa wie folgt aussehen

MQL5
 |--- include
 |--- |--- Connexus
 |--- |--- |--- Data
 |--- |--- |--- |--- Json.mqh
 |--- |--- |--- URL
 |--- |--- |--- |--- QueryParam.mqh
 |--- |--- |--- |--- URL.mqh


QueryParam

Beginnen wir mit der Klasse CQueryParam. Diese Klasse ist für das Hinzufügen, Entfernen, Suchen und Serialisieren von Abfrageparametern zuständig und bietet außerdem Hilfsmethoden wie das Bereinigen von Daten und das Parsen von Abfragezeichenfolgen. Wir beginnen mit der Erstellung der Klasse mit einem privaten Objekt vom Typ CJson, um die Abfrageparameter als Schlüssel-Wert-Paare zu speichern.

//+------------------------------------------------------------------+
//| class : CQueryParam                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CQueryParam                                        |
//| Heritage    : No heritage                                        |
//| Description : Manages query parameters for HTTP requests         |
//|                                                                  |
//+------------------------------------------------------------------+
class CQueryParam
  {
private:

   CJson             m_query_param;                      // Storage for query parameters

public:
                     CQueryParam(void);
                    ~CQueryParam(void);

   //--- Functions to manage query parameters
   void              AddParam(string key, string value); // Add a key-value pair
   void              AddParam(string param);             // Add a single key-value parameter
   void              AddParams(const string &params[]);  // Add multiple parameters
   void              RemoveParam(const string key);      // Remove a parameter by key
   string            GetParam(const string key) const;   // Retrieve a parameter value by key
   bool              HasParam(const string key);         // Check if parameter exists
   int               ParamSize(void);                    // Get the number of parameters

   //--- Auxiliary methods
   bool              Parse(const string query_param);    // Parse a query string
   string            Serialize(void);                    // Serialize parameters into a query string
   void              Clear(void);                        // Clear all parameters
  };

Lassen Sie uns nun die wichtigsten Methoden untersuchen und verstehen, wie jede von ihnen zum Funktionieren der Klasse beiträgt.

  • AddParam(string key, string value): Diese Methode ist für das Hinzufügen eines neuen Parameters zur Liste der Abfrageparameter zuständig. Sie erhält den Schlüssel und den Wert als Parameter und speichert sie im Objekt m_query_param.
  • AddParam(string param): Diese Methode fügt einen Parameter hinzu, der bereits als Schlüssel=Wert formatiert ist. Sie prüft, ob die Zeichenkette das Zeichen = enthält, und wenn ja, teilt sie die Zeichenkette in zwei Werte auf, einen für den Schlüssel und einen für den Wert, und speichert sie.
  • AddParams(const string &params[]): Diese Methode fügt mehrere Parameter auf einmal hinzu. Sie übernimmt ein Array von Strings im Format Schlüssel=Wert und ruft die Methode AddParam für jedes Element im Array auf.
  • RemoveParam(const string key): Mit dieser Methode wird ein Parameter aus der Liste der Abfrageparameter entfernt. Sie findet den Schlüssel und entfernt ihn aus dem Objekt m_query_param. - GetParam(const string key): Diese Methode gibt den Wert eines bestimmten Parameters zurück, wobei der Schlüssel als Eingabe verwendet wird.
  • HasParam(const string key): Diese Methode prüft, ob ein bestimmter Parameter bereits hinzugefügt wurde.
  • ParamSize(void): Diese Methode gibt die Anzahl der gespeicherten Abfrageparameter zurück.
  • Parse(const string query_param): Die Methode Parse() empfängt eine Zeichenkette mit Abfrageparametern, wandelt sie in Schlüssel-Wert-Paare um und speichert sie im Objekt m_query_param. Es teilt die Zeichenfolge durch die Zeichen & (die die Parameter trennen) und = (das Schlüssel und Wert trennt).
  • Serialize(void): Die Methode Serialize() erzeugt eine formatierte Zeichenkette mit allen gespeicherten Abfrageparametern. Es verkettet die Parameter im Format Schlüssel=Wert und trennt jedes Paar mit &.
  • Clear(void): Die Methode Clear() löscht alle gespeicherten Parameter und setzt das Objekt zurück.

Nachfolgend finden Sie den Code mit den implementierten Funktionen. Denken Sie daran, den CJSON-Import hinzuzufügen:

//+------------------------------------------------------------------+
//| Include the file CJson class                                     |
//+------------------------------------------------------------------+
#include "../Data/Json.mqh"
//+------------------------------------------------------------------+
//| class : CQueryParam                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CQueryParam                                        |
//| Heritage    : No heritage                                        |
//| Description : Manages query parameters for HTTP requests         |
//|                                                                  |
//+------------------------------------------------------------------+
class CQueryParam
  {
private:

   CJson             m_query_param;                      // Storage for query parameters

public:
                     CQueryParam(void);
                    ~CQueryParam(void);

   //--- Functions to manage query parameters
   void              AddParam(string key, string value); // Add a key-value pair
   void              AddParam(string param);             // Add a single key-value parameter
   void              AddParams(const string &params[]);  // Add multiple parameters
   void              RemoveParam(const string key);      // Remove a parameter by key
   string            GetParam(const string key) const;   // Retrieve a parameter value by key
   bool              HasParam(const string key);         // Check if parameter exists
   int               ParamSize(void);                    // Get the number of parameters

   //--- Auxiliary methods
   bool              Parse(const string query_param);    // Parse a query string
   string            Serialize(void);                    // Serialize parameters into a query string
   void              Clear(void);                        // Clear all parameters
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CQueryParam::CQueryParam(void)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CQueryParam::~CQueryParam(void)
  {
  }
//+------------------------------------------------------------------+
//| Adds a key-value pair to the query parameters                    |
//+------------------------------------------------------------------+
void CQueryParam::AddParam(string key, string value)
  {
   m_query_param[key] = value;
  }
//+------------------------------------------------------------------+
//| Adds a single parameter from a formatted string                  |
//+------------------------------------------------------------------+
void CQueryParam::AddParam(string param)
  {
   //--- Check if the input string contains an "=" symbol, which indicates a key-value pair
   if(StringFind(param,"=") >= 0)
     {
      //--- Declare an array to hold the key and value after splitting the string
      string key_value[];
      
      //--- Split the input string using "=" as the delimiter and store the result in the key_value array
      int size = StringSplit(param,StringGetCharacter("=",0),key_value);
      
      //--- If the size of the split result is exactly 2 (meaning a valid key-value pair was found)
      if(size == 2)
        {
         // Add the key-value pair to the m_query_param map
         // key_value[0] is the key, key_value[1] is the value
         m_query_param[key_value[0]] = key_value[1];
        }
     }
  }
//+------------------------------------------------------------------+
//| Adds multiple parameters from an array of formatted strings      |
//+------------------------------------------------------------------+
void CQueryParam::AddParams(const string &params[])
  {
   //--- Get the size of the input array 'params'
   int size = ArraySize(params);
   
   //--- Loop through each element in the 'params' array.
   for(int i=0;i<size;i++)
     {
      //--- Call the AddParam function to add each parameter to the m_query_param map.
      this.AddParam(params[i]);
     }
  }
//+------------------------------------------------------------------+
//| Removes a parameter by key                                       |
//+------------------------------------------------------------------+
void CQueryParam::RemoveParam(const string key)
  {
   m_query_param.Remove(key);
  }
//+------------------------------------------------------------------+
//| Retrieves a parameter value by key                               |
//+------------------------------------------------------------------+
string CQueryParam::GetParam(const string key) const
  {
   return(m_query_param[key].ToString());
  }
//+------------------------------------------------------------------+
//| Checks if a parameter exists by key                              |
//+------------------------------------------------------------------+
bool CQueryParam::HasParam(const string key)
  {
   return(m_query_param.FindKey(key) != NULL);
  }
//+------------------------------------------------------------------+
//| Returns the number of parameters stored                          |
//+------------------------------------------------------------------+
int CQueryParam::ParamSize(void)
  {
   return(m_query_param.Size());
  }
//+------------------------------------------------------------------+
//| Parses a query string into parameters                            |
//| Input: query_param - A string formatted as a query parameter     |
//| Output: bool - Always returns true, indicating successful parsing|
//+------------------------------------------------------------------+
bool CQueryParam::Parse(const string query_param)
  {
   //--- Split the input string by '&', separating the individual parameters
   string params[];
   int size = StringSplit(query_param, StringGetCharacter("&",0), params);

   //--- Iterate through each parameter string
   for(int i=0; i<size; i++)
     {
      //--- Split each parameter string by '=', separating the key and value
      string key_value[];
      StringSplit(params[i], StringGetCharacter("=",0), key_value);

      //--- Check if the split resulted in exactly two parts: key and value
      if (ArraySize(key_value) == 2)
        {
         //--- Assign the value to the corresponding key in the map
         m_query_param[key_value[0]] = key_value[1];
        }
     }
   //--- Return true indicating that parsing was successful
   return(true);
  }
//+------------------------------------------------------------------+
//| Serializes the stored parameters into a query string             |
//| Output: string - A string representing the serialized parameters |
//+------------------------------------------------------------------+
string CQueryParam::Serialize(void)
  {
   //--- Initialize an empty string to build the query parameter string
   string query_param = "";

   //--- Iterate over each key-value pair in the parameter map
   for(int i=0; i<m_query_param.Size(); i++)
     {
      //--- Append a '?' at the beginning to indicate the start of parameters
      if(i == 0)
        {
         query_param = "?";
        }

      //--- Construct each key-value pair as 'key=value'
      if(i == m_query_param.Size()-1)
        {
         //--- If it's the last pair, don't append '&'
         query_param += m_query_param[i].m_key + "=" + m_query_param[i].ToString();
        }
      else
        {
         //--- Otherwise, append '&' after each pair
         query_param += m_query_param[i].m_key + "=" + m_query_param[i].ToString() + "&";
        }
     }

   //--- Return the constructed query parameter string
   return(query_param);
  }
//+------------------------------------------------------------------+
//| Clears all stored parameters                                     |
//+------------------------------------------------------------------+
void CQueryParam::Clear(void)
  {
   m_query_param.Clear();
  }
//+------------------------------------------------------------------+


URL

Nun, da wir eine Klasse haben, die für die Arbeit mit Abfrageparametern verantwortlich ist, arbeiten wir an der Klasse CURL, die den Rest erledigen wird, indem sie Protokoll, Host, Port usw. verwendet. Hier ist eine erste Implementierung der CURL-Klasse in MQL5, die eingebunden werden muss:

//+------------------------------------------------------------------+
//|                                                          URL.mqh |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#include "QueryParam.mqh"
class CURL
  {
public:
                     CURL(void);
                    ~CURL(void);
  };
CURL::CURL(void)
  {
  }
CURL::~CURL(void)
  {
  }
//+------------------------------------------------------------------+

Erstellen wir eine ENUM erstellen, die die gängigsten Protokolle enthält:

//+------------------------------------------------------------------+
//| Enum to represent different URL protocol                         |
//+------------------------------------------------------------------+
enum ENUM_URL_PROTOCOL
  {
   URL_PROTOCOL_NULL = 0,  // No protocol defined
   URL_PROTOCOL_HTTP,      // HTTP protocol
   URL_PROTOCOL_HTTPS,     // HTTPS protocol
   URL_PROTOCOL_WS,        // WebSocket (WS) protocol
   URL_PROTOCOL_WSS,       // Secure WebSocket (WSS) protocol
   URL_PROTOCOL_FTP        // FTP protocol
  };

In das private Feld der Klasse fügen wir eine Struktur ein, die die grundlegenden Elemente einer URL bildet, und eine Instanz dieser Struktur namens m_url

private:
   
   //--- Structure to hold components of a URL
   struct MqlURL
     {
      ENUM_URL_PROTOCOL protocol;      // URL protocol
      string            host;          // Host name or IP
      uint              port;          // Port number
      string            path;          // Path after the host
      CQueryParam       query_param;   // Query parameters as key-value pairs
     };
   MqlURL            m_url;            // Instance of MqlURL to store the URL details

Wir erstellen die „Setter“ und „Getter“ und ihre Implementierungen

//+------------------------------------------------------------------+
//| class : CURL                                                     |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CURL                                               |
//| Heritage    : No heritage                                        |
//| Description : Define a class CURL to manage and manipulate URLs  |
//|                                                                  |
//+------------------------------------------------------------------+
class CURL
  {
public:
                     CURL(void);
                    ~CURL(void);
   
   
   //--- Methods to access and modify URL components
   ENUM_URL_PROTOCOL Protocol(void) const;                  // Get the protocol
   void              Protocol(ENUM_URL_PROTOCOL protocol);  // Set the protocol
   string            Host(void) const;                      // Get the host
   void              Host(const string host);               // Set the host
   uint              Port(void) const;                      // Get the port
   void              Port(const uint port);                 // Set the port
   string            Path(void) const;                      // Get the path
   void              Path(const string path);               // Set the path
   CQueryParam       *QueryParam(void);                     // Access query parameters
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CURL::CURL(void)
  {
   this.Clear();
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CURL::~CURL(void)
  {
  }
//+------------------------------------------------------------------+
//| Getter for protocol                                              |
//+------------------------------------------------------------------+
ENUM_URL_PROTOCOL CURL::Protocol(void) const
  {
   return(m_url.protocol);
  }
//+------------------------------------------------------------------+
//| Setter for protocol                                              |
//+------------------------------------------------------------------+
void CURL::Protocol(ENUM_URL_PROTOCOL protocol)
  {
   m_url.protocol = protocol;
  }
//+------------------------------------------------------------------+
//| Getter for host                                                  |
//+------------------------------------------------------------------+
string CURL::Host(void) const
  {
   return(m_url.host);
  }
//+------------------------------------------------------------------+
//| Setter for host                                                  |
//+------------------------------------------------------------------+
void CURL::Host(const string host)
  {
   m_url.host = host;
  }
//+------------------------------------------------------------------+
//| Getter for port                                                  |
//+------------------------------------------------------------------+
uint CURL::Port(void) const
  {
   return(m_url.port);
  }
//+------------------------------------------------------------------+
//| Setter for port                                                  |
//+------------------------------------------------------------------+
void CURL::Port(const uint port)
  {
   m_url.port = port;
  }
//+------------------------------------------------------------------+
//| Getter for path                                                  |
//+------------------------------------------------------------------+
string CURL::Path(void) const
  {
   return(m_url.path);
  }
//+------------------------------------------------------------------+
//| Setter for path                                                  |
//+------------------------------------------------------------------+
void CURL::Path(const string path)
  {
   m_url.path = path;
  }
//+------------------------------------------------------------------+
//| Accessor for query parameters (returns a pointer)                |
//+------------------------------------------------------------------+
CQueryParam *CURL::QueryParam(void)
  {
   return(GetPointer(m_url.query_param));
  }
//+------------------------------------------------------------------+

Jetzt werden wir an der Engine unserer Klasse arbeiten, indem wir neue Funktionen hinzufügen, um mit diesen Daten zu arbeiten, sie sind:

  • Clear(void) : Die Methode Clear() ist dafür verantwortlich, alle in der Klasse gespeicherten Daten zu löschen und ihre Attribute auf leere oder Standardwerte zurückzusetzen. Diese Methode ist nützlich, wenn Sie die Klasseninstanz wiederverwenden möchten, um eine neue URL zu erstellen, oder wenn Sie sicherstellen müssen, dass keine alten Daten versehentlich in eine neue Operation aufgenommen werden. Mit anderen Worten, die Klasse wird „zurückgesetzt“ und alle zuvor gespeicherten Informationen werden entfernt.

    So funktioniert es:

    • Setzt die Klassenattribute je nach Datentyp auf leer oder null (leerer String für Protokoll, Domäne usw.).
    • Entfernt alle Abfrageparameter und setzt den Pfad auf den Standardwert zurück.
    • Nach dem Aufruf von Clear() befindet sich die Klasseninstanz in einem Anfangszustand, als ob sie gerade erst erstellt worden wäre.


    Beispiel:

    Wenn die Klasse zuvor gespeichert wurde:

    • Protocol: https
    • Domain: api.example.com
    • Path: /v1/users
    • Query Params: id=123&active=true


    Nach dem Aufruf von Clear() werden alle diese Werte auf zurückgesetzt:

    • Protocol: ""
    • Domain: ""
    • Path: ""
    • Query Params: ""


    Damit ist die Klasse in der Lage, eine neue URL von Grund auf zu erstellen.

  • BaseUrl(void) : Diese Methode ist für die Erzeugung und Rückgabe des Basisteils der URL zuständig, der sich aus dem Protokoll (z. B. http , https ), der Domäne (z. B. www.example.com ) und optional dem Port (z. B. :8080 ) zusammensetzt. Die Methode gewährleistet, dass die wesentlichen Elemente für die Kommunikation mit dem Server korrekt sind. Mit dieser Methode haben Sie die Möglichkeit, dynamische URLs zusammenzustellen, wobei Sie immer vom Basisteil ausgehen. Dies kann nützlich sein, wenn Sie die Basis der URL für den Zugriff auf verschiedene Ressourcen auf demselben Server wiederverwenden möchten.

  • PathAndQuery(void) : Diese Methode ist für die Generierung des Pfadteils der Ressource und die Verkettung der Abfrageparameter zuständig, die Sie zuvor hinzugefügt haben. Der Pfad gibt in der Regel die Ressource an, auf die Sie auf dem Server zugreifen möchten, während Sie mit den Abfrageparametern zusätzliche Details wie Filter oder Paginierung angeben können. Indem Sie den Pfad und die Abfrageparameter von der Basis-URL trennen, können Sie die verschiedenen Teile der URL übersichtlicher zusammenstellen. Diese Methode gibt eine Zeichenkette zurück, die direkt in einer HTTP-Anfrage oder in anderen Methoden verwendet werden kann, die diese Struktur benötigen.

  • FullUrl(void) : Dies ist die Methode, die alle Teile der URL „kompiliert“ und die vollständige, gebrauchsfertige URL zurückgibt. Sie kombiniert BaseURL() und PathAndQuery(), um die endgültige URL zu bilden, die Sie direkt in einer HTTP-Anfrage verwenden können. Wenn Sie die vollständige URL benötigen, um eine HTTP-Anfrage zu senden, ist diese Methode der einfachste Weg, um sicherzustellen, dass die URL richtig formatiert ist. Dadurch werden Fehler vermieden, wie z. B. das Vergessen, die Basis- und Abfrageparameter zu verketten.

    Beispiel: Wenn die Klasse die folgenden Werte gespeichert hat:

    • Protocol: https
    • Domain: api.example.com
    • Path: /v1/users
    • Query Params: id=123&active=true


    Wenn Sie Serialize() aufrufen, gibt die Funktion Folgendes zurück:

    https://api.exemplo.com/v1/users?id=123&active=true

  • Parse(const string url) : Macht das Gegenteil von FullUrl(void) . Es nimmt eine vollständige URL als Argument und trennt ihre Komponenten in einer organisierten Weise. Ziel ist es, eine URL in kleinere Teile zu zerlegen (Protokoll, Domäne, Port, Pfad, Abfrageparameter usw.), sodass der Programmierer mit diesen Elementen einzeln arbeiten kann. Dies ist besonders nützlich, wenn Sie eine URL erhalten und deren Details verstehen oder programmatisch ändern müssen.

    So funktioniert es:

    • Empfängt eine Zeichenkette mit einer vollständigen URL.
    • Analysiert (oder „parst“) die Zeichenfolge und identifiziert jeden Teil der URL: das Protokoll ( http , https ), die Domäne, den Port (falls vorhanden), den Pfad und alle Abfrageparameter.
    • Weist diese Werte den internen Attributen der Klasse zu, wie z. B. protocol, host, path, queryParams und behandelt die Trennzeichen wie :// , / , ? und & korrekt, um die URL in ihre Teile zu zerlegen.


    Beispiel: eine gegebene URL:

    https://api.example.com:8080/v1/users?id=123&active=true

    Beim Aufruf von Parse() weist die Funktion die folgenden Werte zu:

    • Protocol: https
    • Domain: api.example.com
    • Port: 8080
    • Path: /v1/users
    • Query Params: id=123 , active=true


    So können Sie auf jeden Teil der URL programmtechnisch zugreifen, was die Manipulation oder das Parsen der URL erleichtert.

  • UrlProtocolToStr(ENUM_URL_PROTOCOL protocol) : Gibt das Protokoll in einer Zeichenkette zurück, nützlich z.B. für die Umwandlung von ENUM_URL_PROTOCOL in eine einfache Zeichenkette:

    • URL_PROTOCOL_HTTP → „http“
    • URL_PROTOCOL_HTTPS → „httpS“
    • URL_PROTOCOL_WSS → „wss“
    • usw...

Jede dieser Methoden spielt eine wesentliche Rolle bei der Konstruktion und Manipulation von URLs. Mit diesen Funktionen wird die Connexus-Bibliothek äußerst flexibel, um den dynamischen Anforderungen von APIs gerecht zu werden, unabhängig davon, ob URLs von Grund auf neu erstellt oder bestehende URLs geparst werden. Durch die Implementierung dieser Methoden können Entwickler URLs programmatisch zusammenstellen, wodurch Fehler vermieden und die Kommunikation mit Servern optimiert werden. Nachstehend finden Sie den Code mit den implementierten Funktionen:

//+------------------------------------------------------------------+
//| Define constants for different URL protocols                     |
//+------------------------------------------------------------------+
#define HTTP "http"
#define HTTPS "https"
#define WS "ws"
#define WSS "wss"
#define FTP "ftp"
//+------------------------------------------------------------------+
//| class : CURL                                                     |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CURL                                               |
//| Heritage    : No heritage                                        |
//| Description : Define a class CURL to manage and manipulate URLs  |
//|                                                                  |
//+------------------------------------------------------------------+
class CURL
  {
private:
   string            UrlProtocolToStr(ENUM_URL_PROTOCOL protocol); // Helper method to convert protocol enum to string
   
public:
   //--- Methods to parse and serialize the URL
   void              Clear(void);                           // Clear/reset the URL
   string            BaseUrl(void);                         // Return the base URL (protocol, host, port)
   string            PathAndQuery(void);                    // Return the path and query part of the URL
   string            FullUrl(void);                         // Return the complete URL
   bool              Parse(const string url);               // Parse a URL string into components
  };
//+------------------------------------------------------------------+
//| Convert URL protocol enum to string                              |
//+------------------------------------------------------------------+
string CURL::UrlProtocolToStr(ENUM_URL_PROTOCOL protocol)
  {
   if(protocol == URL_PROTOCOL_HTTP)   { return(HTTP);   }
   if(protocol == URL_PROTOCOL_HTTPS)  { return(HTTPS);  }
   if(protocol == URL_PROTOCOL_WS)     { return(WS);     }
   if(protocol == URL_PROTOCOL_WSS)    { return(WSS);    }
   if(protocol == URL_PROTOCOL_FTP)    { return(FTP);    }
   return(NULL);
  }
//+------------------------------------------------------------------+
//| Clear or reset the URL structure                                 |
//+------------------------------------------------------------------+
void CURL::Clear(void)
  {
   m_url.protocol = URL_PROTOCOL_NULL;
   m_url.host = "";
   m_url.port = 0;
   m_url.path = "";
   m_url.query_param.Clear();
  }
//+------------------------------------------------------------------+
//| Construct the base URL from protocol, host, and port             |
//+------------------------------------------------------------------+
string CURL::BaseUrl(void)
  {
   //--- Checks if host is not null or empty
   if(m_url.host != "" && m_url.host != NULL)
     {
      MqlURL url = m_url;
      
      //--- Set default protocol if not defined
      if(url.protocol == URL_PROTOCOL_NULL)
        {
         url.protocol = URL_PROTOCOL_HTTPS;
        }
      
      //--- Set default port based on the protocol
      if(url.port == 0)
        {
         url.port = (url.protocol == URL_PROTOCOL_HTTPS) ? 443 : 80;
        }
      
      //--- Construct base URL (protocol + host)
      string serialized_url = this.UrlProtocolToStr(url.protocol) + "://" + url.host;
      
      //--- Include port in URL only if it's not the default port for the protocol
      if(!(url.protocol == URL_PROTOCOL_HTTP && url.port == 80) &&
         !(url.protocol == URL_PROTOCOL_HTTPS && url.port == 443))
        {
         serialized_url += ":" + IntegerToString(m_url.port);
        }
      
      return(serialized_url);
     }
   else
     {
      return("Error: Invalid host");
     }
  }
//+------------------------------------------------------------------+
//| Construct path and query string from URL components              |
//+------------------------------------------------------------------+
string CURL::PathAndQuery(void)
  {
   MqlURL url = m_url;
   
   //--- Ensure path starts with a "/"
   if(url.path == "")
     {
      url.path = "/";
     }
   else if(StringGetCharacter(url.path,0) != '/')
     {
      url.path = "/" + url.path;
     }
   
   //--- Remove any double slashes from the path
   StringReplace(url.path,"//","/");
   
   //--- Check for invalid spaces in the path
   if(StringFind(url.path," ") >= 0)
     {
      return("Error: Invalid characters in path");
     }
   
   //--- Return the full path and query string
   return(url.path + url.query_param.Serialize());
  }
//+------------------------------------------------------------------+
//| Return the complete URL (base URL + path + query)                |
//+------------------------------------------------------------------+
string CURL::FullUrl(void)
  {
   return(this.BaseUrl() + this.PathAndQuery());
  }
//+------------------------------------------------------------------+
//| Parse a URL string and extract its components                    |
//+------------------------------------------------------------------+
bool CURL::Parse(const string url)
  {
   //--- Create an instance of MqlURL to hold the parsed data
   MqlURL urlObj;
   
   //--- Parse protocol from the URL
   int index_end_protocol = 0;
   
   //--- Check if the URL starts with "http://"
   if(StringFind(url,"http://") >= 0)
     {
      urlObj.protocol = URL_PROTOCOL_HTTP;
      index_end_protocol = 7;
     }
   else if(StringFind(url,"https://") >= 0)
     {
      urlObj.protocol = URL_PROTOCOL_HTTPS;
      index_end_protocol = 8;
     }
   else if(StringFind(url,"ws://") >= 0)
     {
      urlObj.protocol = URL_PROTOCOL_WS;
      index_end_protocol = 5;
     }
   else if(StringFind(url,"wss://") >= 0)
     {
      urlObj.protocol = URL_PROTOCOL_WSS;
      index_end_protocol = 6;
     }
   else if(StringFind(url,"ftp://") >= 0)
     {
      urlObj.protocol = URL_PROTOCOL_FTP;
      index_end_protocol = 6;
     }
   else
     {
      return(false); // Unsupported protocol
     }
   
   //--- Separate the endpoint part after the protocol
   string endpoint = StringSubstr(url,index_end_protocol);  // Get the URL part after the protocol
   string parts[];                                          // Array to hold the split components of the URL
   
   //--- Split the endpoint by the "/" character to separate path and query components
   int size = StringSplit(endpoint,StringGetCharacter("/",0),parts);
   
   //--- Handle the host and port part of the URL
   string host_port[];
   
   //--- If the first part (host) contains a colon (":"), split it into host and port
   if(StringSplit(parts[0],StringGetCharacter(":",0),host_port) > 1)
     {
      urlObj.host = host_port[0];                        // Set the host
      urlObj.port = (uint)StringToInteger(host_port[1]); // Convert and set the port
     }
   else
     {
      urlObj.host = parts[0];
      
      //--- Set default port based on the protocol
      if(urlObj.protocol == URL_PROTOCOL_HTTP)
        {
         urlObj.port = 80;
        }
      if(urlObj.protocol == URL_PROTOCOL_HTTPS)
        {
         urlObj.port = 443;
        }
     }
   
   //--- If there's no path, default to "/"
   if(size == 1)
     {
      urlObj.path += "/"; // Add a default root path "/"
     }
   
   //--- Loop through the remaining parts of the URL (after the host)
   for(int i=1;i<size;i++)
     {
      //--- If the path contains an empty part, return false (invalid URL)
      if(parts[i] == "")
        {
         return(false);
        }
      //--- If the part contains a "?" (indicating query parameters)
      else if(StringFind(parts[i],"?") >= 0)
        {
         string resource_query[];
         
         //--- Split the part by "?" to separate the resource and query
         if(StringSplit(parts[i],StringGetCharacter("?",0),resource_query) > 0)
           {
            urlObj.path += "/"+resource_query[0];
            urlObj.query_param.Parse(resource_query[1]);
           }
        }
      else
        {
         //--- Otherwise, add to the path as part of the URL
         urlObj.path += "/"+parts[i];
        }
     }
   
   //--- Assign the parsed URL object to the member variable
   m_url = urlObj;
   return(true);
  }
//+------------------------------------------------------------------+

Schließlich fügen wir zwei weitere neue Funktionen hinzu, die den Entwicklern helfen sollen, und zwar:

  • ShowData(void): Druckt die URL-Elemente separat aus, um die Fehlersuche zu erleichtern und zu verstehen, welche Daten in der Klasse gespeichert sind. Zum Beispiel:

https://api.exemplo.com/v1/users?id=123&active=true

Die Funktion sollte dies zurückgeben:

Protocol: https
Host: api.exemplo.com
Port: 443
Path: /v1/users
Query Param: {
   "id":123,
   "active":true
}

  • Compare(CURL &url): Diese Funktion empfängt eine weitere Instanz der CURL-Klasse. Sie sollte true zurückgeben, wenn die in beiden Instanzen gespeicherten URLs gleich sind, andernfalls sollte sie false zurückgeben. Es kann nützlich sein, den Vergleich von serialisierten URLs zu vermeiden, um Zeit zu sparen. Beispiel ohne die Funktion Compare()
    // Example without using the Compare() method
    CURl url1;
    CURl url2;
    
    if(url1.FullUrl() == url2.FullUrl())
      {
       Print("Equals URL");
      }
    
    
    // Example with method Compare()
    CURl url1;
    CURl url2;
    
    if(url1.Compare(url2))
      {
       Print("Equals URL");
      }
        
    
        
    

Nachfolgend finden Sie den Code für die Implementierung jeder dieser Funktionen:

//+------------------------------------------------------------------+
//| class : CURL                                                     |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CURL                                               |
//| Heritage    : No heritage                                        |
//| Description : Define a class CURL to manage and manipulate URLs  |
//|                                                                  |
//+------------------------------------------------------------------+
class CURL
  {
public:
   //--- Auxiliary methods
   bool              Compare(CURL &url);                    // Compare two URLs
   string            ShowData();                            // Show URL details as a string
  };
//+------------------------------------------------------------------+
//| Compare the current URL with another URL                         |
//+------------------------------------------------------------------+
bool CURL::Compare(CURL &url)
  {
   return (m_url.protocol == url.Protocol() &&
           m_url.host == url.Host() &&
           m_url.port == url.Port() &&
           m_url.path == url.Path() &&
           m_url.query_param.Serialize() == url.QueryParam().Serialize());
  }
//+------------------------------------------------------------------+
//| Display the components of the URL as a formatted string          |
//+------------------------------------------------------------------+
string CURL::ShowData(void)
  {
   return(
      "Protocol: "+EnumToString(m_url.protocol)+"\n"+
      "Host: "+m_url.host+"\n"+
      "Port: "+IntegerToString(m_url.port)+"\n"+
      "Path: "+m_url.path+"\n"+
      "Query Param: "+m_url.query_param.Serialize()+"\n"
   );
  }
//+------------------------------------------------------------------+

Wir haben beide Klassen für die Arbeit mit URLs fertiggestellt, gehen wir nun zum Testen über.


Tests

Nun, da wir unsere ersten Klassen fertig haben, lassen Sie uns URLs durch die Klassen erstellen und auch den umgekehrten Prozess machen, von einer URL werden wir das Element mit der Klasse trennen. Um die Tests durchzuführen, werde ich eine Datei mit dem Namen TestUrl.mq5 im folgendem Pfad erstellen: Experts/Connexus/TestUrl.mq5.

int OnInit()
  {
   //--- Creating URL
   CURL url;
   url.Host("example.com");
   url.Path("/api/v1/data");
   Print("Test1 | # ",url.FullUrl() == "https://example.com/api/v1/data");
   
   //--- Changing parts of the URL
   url.Host("api.example.com");
   Print("Test2 | # ",url.FullUrl() == "https://api.example.com/api/v1/data");
   
   //--- Parse URL
   url.Clear();
   string url_str = "https://api.example.com/api/v1/data";
   Print("Test3 | # ",url.Parse(url_str));
   Print("Test3 | - Protocol # ",url.Protocol() == URL_PROTOCOL_HTTPS);
   Print("Test3 | - Host # ",url.Host() == "api.example.com");
   Print("Test3 | - Port # ",url.Port() == 443);
   Print("Test3 | - Path # ",url.Path() == "/api/v1/data");
   
//---
   return(INIT_SUCCEEDED);
  }

Wenn wir den EA ausführen, haben wir die folgenden Daten im Terminal:

Test1 | # true
Test2 | # true
Test3 | # true
Test3 | - Protocol # true
Test3 | - Host # true
Test3 | - Port # true
Test3 | - Path # true


Schlussfolgerung

In diesem Artikel haben wir uns eingehend mit der Funktionsweise des HTTP-Protokolls befasst, angefangen bei grundlegenden Konzepten wie den HTTP-Verben (GET, POST, PUT, DELETE) bis hin zu den Antwortstatuscodes, die uns helfen, die Antwort auf eine Anfrage zu interpretieren. Um die Verwaltung von URLs in Ihren MQL5-Anwendungen zu vereinfachen, haben wir die Klasse „CQueryParam“ entwickelt, die einen einfachen und effizienten Weg zur Manipulation von Abfrageparametern bietet. Darüber hinaus haben wir die Klasse „CURL“ implementiert, die eine dynamische Änderung von Teilen der URL ermöglicht, wodurch der Prozess der Erstellung und Bearbeitung von HTTP-Anfragen flexibler und robuster wird.

Mit diesen Ressourcen verfügen Sie bereits über eine gute Grundlage für die Integration Ihrer Anwendungen mit externen APIs, die die Kommunikation zwischen Ihrem Code und Webservern erleichtern. Wir stehen jedoch erst am Anfang. Im nächsten Artikel werden wir unsere Reise in die HTTP-Welt fortsetzen, wo wir dedizierte Klassen erstellen werden, um mit den **Headern** und **Body** von Anfragen zu arbeiten, was noch mehr Kontrolle über HTTP-Interaktionen ermöglicht.

Bleiben Sie auf dem Laufenden, denn wir bauen eine wichtige Bibliothek auf, die Ihre Fähigkeiten zur API-Integration auf die nächste Stufe heben wird!

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

Entwicklung eines Replay Systems (Teil 52): Die Dinge werden kompliziert (IV) Entwicklung eines Replay Systems (Teil 52): Die Dinge werden kompliziert (IV)
In diesem Artikel werden wir den Mauszeiger ändern, um die Interaktion mit dem Kontrollindikator zu ermöglichen und einen zuverlässigen und stabilen Betrieb zu gewährleisten.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 40): Parabolic SAR MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 40): Parabolic SAR
Der parabolische Stop-and-Reversal (SAR) ist ein Indikator für Trendbestätigungs- und Trendbeendigungspunkte. Da er bei der Erkennung von Trends hinterherhinkt, bestand sein Hauptzweck in der Positionierung von nachlaufenden Stop-Losses für offene Positionen. Wir untersuchen jedoch, ob es tatsächlich als Expert Advisor-Signal verwendet werden kann, dank der nutzerdefinierten Signalklassen der vom Assistenten zusammengestellten Expert Advisors.
Entwicklung eines Replay Systems (Teil 53): Die Dinge werden kompliziert (V) Entwicklung eines Replay Systems (Teil 53): Die Dinge werden kompliziert (V)
In diesem Artikel behandeln wir ein wichtiges Thema, das nur wenige Menschen verstehen: Nutzerdefinierte Ereignisse. Gefahren. Vor- und Nachteile dieser Elemente. Dieses Thema ist der Schlüssel für diejenigen, die professionelle Programmierer in MQL5 oder einer anderen Sprache werden wollen. Hier werden wir uns auf MQL5 und MetaTrader 5 konzentrieren.
Verschaffen Sie sich einen Vorteil auf jedem Markt (Teil IV): CBOE: Volatilitätsindizes von Euro und Gold Verschaffen Sie sich einen Vorteil auf jedem Markt (Teil IV): CBOE: Volatilitätsindizes von Euro und Gold
Wir werden alternative, von der Chicago Board Of Options Exchange (CBOE) kuratierte Daten analysieren, um die Genauigkeit unserer tiefen neuronalen Netze bei der Vorhersage des XAUEUR-Symbols zu verbessern.