English Русский 中文 Español Deutsch Português
preview
Connexusにおけるヘッダ(第3部):リクエスト用HTTPヘッダの使い方をマスターする

Connexusにおけるヘッダ(第3部):リクエスト用HTTPヘッダの使い方をマスターする

MetaTrader 5 |
111 0
joaopedrodev
joaopedrodev

はじめに

この記事は、Connexusと呼ばれるライブラリを構築する連載の続きです。第1回では、WebRequest関数の基本的な機能を理解し、その各パラメータを理解し、さらにこの関数の使用とその難しさを示すサンプルコードを作成しました。この記事では、HTTP通信におけるヘッダの重要性と有用性、そしてこれらの要素が現代のWebでどのようにさまざまな目的に使用されているかを探ります。

HTTPメッセージの構造は、レスポンスであれリクエストであれ、ヘッダとボディという2つの基本要素で構成されています。それぞれが通信プロセスにおいて役割を持っており、データが組織的、効率的かつ安全な方法で伝送されることを保証します。

まずはじめに、HTTPリクエストとレスポンスの構造がどのように機能するかを簡単に復習しておきましょう。


HTTPリクエストの構造

HTTPリクエストは通常、次のような形式をとります。

HTTP Method | URL | HTTP Version
Headers
Body (Optional)
  • HTTPメソッド:リクエストの意図を定義する(GET、POST、PUT、DELETEなど)
  • URL:要求されているリソースを識別する(これについては、前回の記事で詳しく説明した)
  • HTTPバージョン:使用しているプロトコルのバージョンを指定する
  • ヘッダ:コンテンツタイプ、認証などのリクエストメタデータ
  • ボディ:リクエストの内容(通常、POSTやPUTなどのメソッドに含まれる)


HTTPレスポンスの構造

HTTPレスポンスも同様の構造になっています。

HTTP Version | Status Code | Status Message
Headers
Body (Optional)
  • ステータスコード:結果(200 OK、404 Not Found、500 Internal Server Errorなど)を示す
  • ヘッダ:サイズ、データタイプなど、返されるコンテンツに関する情報
  • ボディ:ページのHTMLやJSONデータなど、レスポンスの実際の内容(ここでの場合、JSONデータを受け取るのが一般的ですが、APIによってはHTMLを返すものもあるので注意が必要)

前回の記事では、URLの形式をより深く掘り下げ、各要素を個別に理解し、それらをグループ化して完全なアドレスを形成しました。この記事では、HTTPリクエストのヘッダについて深く掘り下げ、目的、使い方、可能な値などを見ていきます。


ヘッダ

まず、ヘッダとは何かを理解しましょう。HTTPプロトコルでは、ヘッダはリクエストやレスポンスと一緒に送られる追加データのセットです。HTTPヘッダは、クライアントとサーバの通信に不可欠な機能です。これらの主な目的は、URLやメッセージボディの直接の一部ではない、リクエストについての詳細を提供することです。通信の流れをコントロールし、サーバがデータを正しく解釈処理できるようにコンテキストを提供します。これらのヘッダは、コンテンツタイプ、キャッシュ、認証など、リクエストやレスポンスのコンテキストをサーバとクライアントの両方がよりよく理解するためのものです。言い換えれば、リクエストがどのように処理されるかをサーバに知らせ、レスポンスがどのように解釈されるべきかをクライアントに知らせるメタデータとして機能します。

HTTPヘッダの主な機能をいくつか挙げてみましょう。

  1. 認証:ヘッダの最も一般的な使い方の1つは、クライアントを認証することで、サーバがリクエストを誰が送っているのか、そしてその人がその情報にアクセスできるのかを知ることです。例えば、Authorizationヘッダは、リクエストを処理する前にサーバが受け取り、クライアントを検証するために使用できるトークンや信用証明書を送ります。
  2. キャッシュ制御:Cache-Controlのようなヘッダは、クライアントとサーバがどのようにデータをキャッシュするかを設定することを可能にします。これは、クライアントからサーバへの、あるいはサーバから他のサービスへの不必要なリクエストを避けるのに役立ちます。キャッシュされたデータは、クライアント、プロキシ、その他の中間ポイントに保存することができます。
  3. Content-Typeの指定:Content-Typeヘッダは、クライアントが送受信されるデータのタイプをサーバに通知することを可能にします。通常、JSON、XML、HTMLなどのフォーマットが使用されます。これにより、コミュニケーションの双方がデータを正しく解釈する方法を知ることができます。
  4. コンテントネゴシエーション:クライアントはAcceptヘッダを使って、application/json(サーバはjson形式でデータを送信する)またはtext/html(サーバはhtml形式でデータを送信する)のように、どの応答形式が受け入れられるかをサーバに知らせることができます。これによってサーバは、クライアントが受信できるような形式でレスポンスを送信することができます。最もよく使われるフォーマットはJSONで、ここではそれに焦点を当てるが、他のフォーマットもサポートされています。
  5. セキュリティ:Strict-Transport-Securityなどのヘッダは、HTTPSの使用を強化するのに役立ちます(HTTPSはHTTPと同じですが、Webセキュリティの追加層を含んでいます。リクエスト、レスポンス、ヘッダ、ボディ、URL、その他のフォーマットはまったく同じです。)CORS (Cross Origin Resource Sharing)のような他のヘッダは、どのドメインがAPIのリソースにアクセスできるかを定義し、セキュリティを高めます。このようにして、サーバは情報を送信する相手をフィルタリングし、あらかじめ定義されたドメインにのみ情報を送信することで、そのドメイン以外の人がデータにアクセスできないようにしています。
  6. レート制限:サービスによっては、X-RateLimit-LimitやX-RateLimit-Reamingのようなヘッダを返し、与えられた時間内に許可されるリクエストの数をクライアントに通知します。これにより、多数のリクエストがサーバに過負荷をかけるのを防ぐことができます。

したがって、ヘッダはHTTP通信において重要な役割を果たし、リクエストとレスポンスがどのように処理されるべきかを制御し、明確にし、セキュリティを提供します。


いくつかの可能な値

最も一般的なヘッダの値を見てみましょう。HTTPヘッダは汎用性が高く、クライアントとサーバ間の通信のために必要に応じてカスタマイズできます。ヘッダが含むことができる値は、通信の文脈に依存することを理解します。以下は、最も一般的なヘッダとその値の例です。

  1. Authorization:クライアントからサーバに認証情報または認証トークンを送信し、保護されたリソースへのアクセスを許可するために使用されます。使用する認証方法によって異なる値を取ることができます。認証方法はいくつかありますが、最も一般的に使われているものを見てみましょう。
    • Bearerトークン:特にトークンベースの認証を使用する最近のAPIでは、最も一般的な形式の1つです。この値は通常、ログインまたは認証サーバへの認証後にクライアントが受け取るJWT (JSON Web Token)トークンです。

      Authorization: Bearer <my_token_jwt>

      <my_token_jwt>の値は認証トークンそのもので、通常はBase64エンコードされた長い文字列です。このトークンにはユーザー認証情報が含まれ、有効期限があります。

    • Basic:この値はHTTPベーシック認証を使用し、ユーザー名とパスワードはBase64エンコードされ、ヘッダに直接送られます。クレデンシャルが簡単に解読されるため、この方法は、安全性が低く、HTTPSなしで使用すべきではありません。

      Authorization: Basic base64(username:password)

      値base64(username:password)は、username:passwordのペアをBase64エンコードしたものです。この方法は単純ですが、暗号化された接続で使用されない限り、攻撃に対して脆弱です。

    • Digest:Basicより安全な方法で、クレデンシャルを直接送信する代わりに、ユーザーのクレデンシャルのハッシュを使用します。OAuthやJWTの台頭により今日ではあまり見かけなくなりましたが、一部のAPIではまだ見られます。

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

      username、nonce(一度だけ使用される番号)、realm(認証の範囲)、ハッシュ化された暗号化レスポンスなど、いくつかのフィールドが含まれます。

  1. Content-Type:このヘッダは、リクエストまたは応答のボディに存在するコンテンツのタイプを定義します。よく使われる値をいくつか見てみましょう。
    • application/json:JSONはデータ転送のための軽量で読み書きが容易な形式であるため、APIを扱う場合、これは最も一般的な値です。使用例:

      Content-Type: application/json

    • application/xml:XML (Extensible Markup Language)は、JSON以前から広く使われており、一部のレガシーシステムや古いAPIでは今でも使われていますが、現在のほとんどのAPIはJSON形式をサポートしているので、XMLについては今のところ心配する必要はありません。

      Content-Type: application/xml

    • multipart/form-data:特にクライアントがファイルやフォームデータをアップロードする必要がある場合に、混合データを送信するために使用されます。今のところ、ここで焦点を当てることではありませんが、この可能性があることを知っておくのはいいことです。

    • text/html:送受信するコンテンツがHTMLの場合に使用します。この値はWebページのリクエストとレスポンスでよく使われます。

      Content-Type: text/html

  1. User-Agent:このヘッダは、、クライアントが自分自身を識別するために使用します。通常、リクエストをおこなったデバイス、ブラウザ、オペレーティングシステムのタイプに関するデータを含んでいます。この数値に特別なルールはありませんが、いくつかの基準はあります。
    • Webブラウザ:ブラウザから送信される値には通常、ブラウザ名やバージョン、オペレーティングシステムに関する詳細が含まれています。

      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

    • APIまたはアプリケーション:アプリケーションは、以下のようなカスタム値を使用できます。

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

      これによってサーバは、リクエストが特定のアプリケーションからのものであることを知ることができ、必要に応じてデバッグや監視が容易になります。

  1. Accept:これは、クライアントがどのコンテンツをレスポンスとして受け入れるかを通知するために使用されます。このヘッダに指定できる値はContent-Typeと似ているので、いくつか見てみましょう。
    • application/jsonapplication/xmltext/html:Content-Typeのセッションで見たので、すでにご存知でしょう。

    • image/pngimage/jpegimage/webp:これらの値は、クライアントが画像の受信を期待するときに使われます。例えば、サムネイルや生成されたチャートのようなグラフデータを提供するAPIにおいて、あるいは、ユーザーのアバターやWebサイトのロゴなど、単なる画像です。

      Accept: image/png, image/jpeg

      ここでは、クライアントはPNGとJPEGの両方の画像を受け入れることを通知しています。

    • */*:この値は、クライアントがどのようなタイプのコンテンツもレスポンスとして受け付けることを示します。これは、クライアントが特定の形式を好まない場合や、どのような回答にも対応する用意がある場合に使用されます。



ヘッダを整理する方法

さて、ヘッダが何のためにあるのか、そしていくつかの可能な値を理解したところで、ヘッダがどのように構成されているかを理解しましょう。ヘッダはキーと値のペアで構成され、リクエストに挿入されます。いくつかのヘッダは操作によっては必須ですが、ほとんどはオプションであり、アプリケーションのニーズに依存します。HTTPリクエストの基本ヘッダの例:

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

この例のように、3つのヘッダがあります。

  • Authorization:アクセストークン「token123」を提供します。
  • Content-Type:データの送信方法に関する情報を提供します。
  • User-Agent:サーバがリクエストの処理方法を知るために、サーバに情報を提供します。この例では、「Connexus/1.0 (MetaTrader 5 Terminal)」を使用します。

これらのヘッダは、サーバがリクエストの処理方法を知るための情報を提供します。これは簡単な例に過ぎず、どのセットが最もよく使われ、どのような値が可能で、それぞれが何のためにあるのかについては、すぐに詳しく説明します。


コードを手渡す

ヘッダがどのように機能するのか、何のためにあるのか、どのように使うのかはすでに理解できました。httpbinを覚えておいででしょうか。これは、単にミラーとして機能する無料のサービスです。送信したものはすべて再び返されます。これを使用して、送信するヘッダーと、ターミナル自体が自動的に追加するヘッダーがあるかどうかを確認します。そのために、Experts/Connexus/Test/TestHeader.mq5フォルダにTestHeader.mq5というファイルを作成します。ヘッダに何も送らずにPOSTリクエストを作って、何が返ってくるか見てみましょう。

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

このコードを端末で実行すると、次のようなレスポンスが返ってきます。

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

headersの値に注意してください。端末が自動的に定義したヘッダ値を含む別のjsonオブジェクトが含まれています。リクエストでは、ヘッダにもボディにもデータを送らないことを覚えておいてください。自動的に送信されるこれらのヘッダのそれぞれについて理解しましょう。

  • Accept:前に見たように、これは、クライアントがどのようなタイプのコンテンツをレスポンスとして受け入れても構わないかをサーバに伝えるものです。この場合、先に見たように「/*」という値は、クライアントがどんなタイプのコンテンツでもレスポンスとして受け付けることを意味します。

  • Accept-Encoding:クライアントが受け入れることのできるコンテンツエンコーディングのタイプを指定します。エンコーディングは、ネットワーク帯域幅を節約するためにデータを圧縮するために使用されます。

    • gzip:送信されるレスポンスのサイズを小さくするために使用される圧縮形式です。
    • deflate:これもデータ圧縮の一種で、gzipに似ていますが、アルゴリズムにいくつかの技術的な違いがあります。
  • Accept-Language:このヘッダは、クライアントがどの言語を好むかをサーバに伝えるが、サーバは複数の言語をサポートしなければなりません。これは、サーバがユーザーに最も適した言語でコンテンツを配信するのに役立ちます。

    • pt:クライアントはポルトガル語での返答を希望します。
    • en;q=0.5:enは英語を表し、q=0.5は言語の相対的な優先順位を示す「品質係数」(0から1まで)となります。q=1.0は最大優先度であり、q=0.5は、クライアントは英語を受け入れるが、ポルトガル語を好むことを示します。
  • Content-Length:リクエストボディのサイズをバイト数で示します。この場合、値は0であり、これはコンテンツがないことを意味します。

  • Content-Type:サーバに送信されるデータのタイプを知らせます。この場合、値「application/x-www-form-urlencoded」は、データがURLエンコードされたフォーム形式で送信されたことを意味します。なぜMetaTrader 5がデフォルトでこの形式を設定しているのかはわかりません。

  • Host:リクエストの送信先サーバ名を指定します。これは、特に1つのIPアドレスで複数のドメインにサービスを提供している場合、サーバがどのドメインまたはIPがリクエストされているかを知るために必要です。

  • User-Agent:リクエストをおこなうHTTPクライアント(この場合はMetaTrader 5)を識別する文字列です。使用されているソフトウェアやオペレーティングシステムの詳細が記載されています。

  • X-Amzn-Trace-Id:X-Amzn-Trace-Idヘッダは、AWS (Amazon Web Services)のサービスによって、その分散されたインフラストラクチャ全体のリクエストを追跡するために使用されます。アマゾンのクラウドで実行されているアプリケーションの問題を特定し、デバッグするのに役立ちます。

    • Root=1-66feb3d9-50de44d019af8b0c1058436b:この値は、特定のトランザクションを識別するために使用できる一意のトラッキングIDを表します。診断や性能監視に役立ちます。
    • Meaning:この識別子は、AWSシステムによって自動的に割り当てられ、Amazonインフラストラクチャ内の異なるサービスを通過するリクエストのパスを追跡するために使用することができます。
    • Common usage:このヘッダは、AWSサービスがトラッキングとモニタリング情報を収集するために内部的に使用されます。特にマイクロサービスアーキテクチャにおいて、ボトルネックやレイテンシーの問題を診断するのに役立ちます。

    MetaTrader 5では、プラットフォームなどの診断やバグ修正のために端末からおこなわれたリクエストを追跡できるように、この機能が自動的に追加されていると思います。

MetaTrader 5がデフォルトで追加しているヘッダを確認したので、いくつか変更してみましょう。ヘッダには2つの同一のキーを持つことはできないことに注意してください。つまり、Content-Type: application/jsonとContent-Type: application/x-www-form-urlencodedを使うことはできません。したがって、Content-Typeの値を定義すれば、古い値は上書きされます。いくつかのデータを変更し、以下のヘッダに別の値を定義してみましょう。

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

これらの値を文字列であるheaders_send変数に追加してみましょう。ヘッダとヘッダを区切るために「\n」をつけるのをお忘れなく。以下は修正したコードです。

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

コードを実行すると、このようになります。

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

User-AgentとContent-Typeの値を定義したものに変更したことに注目してください。カスタムヘッダを送信するリクエストの簡単な例ができたので、このヘッダ機能をライブラリに追加してみましょう。私たちの目標は、ヘッダを扱うクラスを作ることです。このクラスは使いやすく、シンプルで直感的なインターフェイスを持ち、ヘッダの追加、削除、更新が簡単にできるものでなければなりません。


HttpHeadersクラスの作成

Connexusフォルダの中に新しいフォルダを作りましょう。この新しいフォルダをHeadersと呼び、その中にHttpHeaders.mqhという新しいファイルを作成します。最終的には以下のようになります。

パス

このファイルには、次のような空のクラスがあるはずです。いくつかコメントを加えました。
//+------------------------------------------------------------------+
//|                                                       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)
  {
  }
//+------------------------------------------------------------------+

これらのヘッダを保存するには、jsonオブジェクトを使用します。jsonキーがヘッダキーとなり、同じようにjson値がヘッダ値となります。そのために、jsonクラスをインポートし、クラス内にm_headersという新しいインスタンスを作成します。

//+------------------------------------------------------------------+
//| Include the file CJson class                                     |
//+------------------------------------------------------------------+
#include "../Data/Json.mqh"
//+------------------------------------------------------------------+
//| class : CHttpHeader                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpHeader                                        |
//| Heritage    : No heritage                                        |
//| Description : Responsible for organizing and storing the headers |
//|               of a request.                                      |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpHeader
  {
private:
   
   CJson             m_headers;
   
public:
                     CHttpHeader(void);
                    ~CHttpHeader(void);
  };
//+------------------------------------------------------------------+

データを格納するjsonオブジェクトの準備ができたので、次のステップでは、このクラスが持つべきメソッドを定義します。最初に、以下のメソッドを作成します。

  • Add(string key, string value) :HTTPリクエストに新しいヘッダを追加するか、すでに存在する場合は更新する
  • Get(string key) :特定のヘッダの名前を指定して、そのヘッダの値を返す
  • Remove(string key) :特定のヘッダを削除する
  • Has(文字列キー) :指定されたキーを持つヘッダが存在するかどうかを確認する
  • Clear() :リクエストからすべてのヘッダを削除する
  • Count() :ヘッダの数を返す

より単純な以下のメソッドをクラスに追加してみましょう。

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

さて、最も単純なメソッドを追加したので、最後にクラスの中心となる2つのメソッドを追加しましょう。

  • Serialize() :HTTPリクエストで送信可能なすべてのヘッダを文字列形式で返します。
  • Parse(string headers) :ヘッダを含む文字列(通常はHTTPレスポンスで受け取る)を、クラスで使用可能な形式に変換します。

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


テスト

クラステストをおこなうために、冒頭で作成したのと同じファイル、TestHeader.mq5を使用します。HttpHeaderファイルをインポートして、CHttpHeaderクラスのインスタンスを作成し、データをクラスに渡します。そして、Serialize()関数を使って文字列としてフォーマットします。

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

端末でこのコードを実行しても、同じレスポンスが返ってきます。

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


結論

要するに、HTTPヘッダとは、授業中に渡すちょっとしたメモのようなもので、サーバがあなたのリクエストに対して何をすべきかを知るためのものです。認証、コンテンツタイプの設定、キャッシングの指示など、さまざまなことができます。それがなければ、コーヒーのサイズや砂糖の量、ミルクの種類を指定せずに注文するのと同じように、HTTPコミュニケーションは混沌としてしまうでしょう。現在、これまでに作成したクラス図は以下のようになっています。

connexusの図

ヘッダとその重要性を理解したところで、さらに興味深いもの、リクエストボディに取り組みましょう。次回は、HTTP通信の核心である、サーバに送信する実際のコンテンツについて掘り下げていきます。結局のところ、内容のないメモを送っても意味がありません。

次の章では、この情報をエレガントかつ効果的にボディ内にパッケージする方法を探ります。またお会いしましょう。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16043

MQL5で取引管理者パネルを作成する(第3回):テーマ管理のための組み込みクラスの拡張(II) MQL5で取引管理者パネルを作成する(第3回):テーマ管理のための組み込みクラスの拡張(II)
このディスカッションでは、既存のダイアログライブラリを慎重に拡張して、テーマ管理ロジックを組み込みます。さらに、管理パネルプロジェクトで使用されるCDialog、CEdit、およびCButtonクラスにテーマ切り替えのメソッドを統合します。さらに洞察力のある視点については、引き続きお読みください。
ボリンジャーバンドを活用したピラニア戦略に基づくMQL5エキスパートアドバイザーの作成 ボリンジャーバンドを活用したピラニア戦略に基づくMQL5エキスパートアドバイザーの作成
この記事では、ボリンジャーバンドを利用したピラニア戦略に基づいてMQL5でエキスパートアドバイザー(EA)を作成し、取引の有効性を高めます。この戦略の重要な原則、コーディングの実装、テストと最適化の方法について説明します。この知識によって、取引シナリオにEAを効果的に導入することが可能になります。
名義変数の順序符号化 名義変数の順序符号化
この記事では、PythonとMQL5の両方を使用して、名義予測値を機械学習アルゴリズムに適した数値フォーマットに変換する方法について議論し、実演します。
MQL5とPythonで自己最適化エキスパートアドバイザーを構築する(第5回):深層マルコフモデル MQL5とPythonで自己最適化エキスパートアドバイザーを構築する(第5回):深層マルコフモデル
この記事では、RSIインジケーターに単純なマルコフ連鎖を適用し、インジケーターが主要なレベルを通過した後の価格の挙動を観察します。NZDJPYペアで最も強い買いシグナルと売りシグナルは、RSIがそれぞれ11~20の範囲と71~80の範囲にあるときに生成されるという結論に達しました。データを操作して、保有するデータから直接学習した最適な取引戦略を作成する方法を説明します。さらに、遷移行列を最適に使用することを学習するためにディープニューラルネットワークを訓練する方法を説明します。