Connexus的头(第三部分):掌握HTTP请求头的使用方法·进阶篇
🔗

Connexus的头(第三部分):掌握HTTP请求头的使用方法·进阶篇

(2/3)· 不少EA卡在WebRequest返回401或乱码,根子常在请求头没拼对,而非URL写错

偏理论进阶 第 2/3 篇
把WebRequest当普通URL抓取器用的交易者,常在POST API时收到401或空响应。问题往往不在地址,而在漏了Content-Type或Authorization头。请求头才是MQL5与外网服务对话的身份证和说明书。

「请求头到底怎么摆」

HTTP 请求头本质是键值对,写进请求里告诉服务端「你是谁、带什么、发什么格式」。上面那段示例里塞了 3 个头:Authorization 带访问令牌 token123,Content-Type 标 JSON,User-Agent 自报是 Connexus/1.0 跑在 MT5 终端。 多数头是可选,只有少数接口强制要某几个。下面这段是最小可发结构,Host 加三个头就能让服务端认人、认格式、认来源。 在 MT5 里用 WebRequest 发请求时,把头按行拼进 string 数组即可;先拿这段原样测通,再按需加减字段,避免一上来堆满冗余头把鉴权搞错。外汇与贵金属接口调用涉及账户与密钥,属高风险操作,令牌泄露可能直接导致资金端暴露。

MQL5 / C++
GET /api/resource HTTP/class="num">1.1
Host: example.com
Authorization: Bearer token123
Content-Type: application/json
User-Agent: Connexus/class="num">1.0 (MetaTrader class="num">5 Terminal)

◍ 用 httpbin 看清 MT5 自动塞了哪些头

想确认 MetaTrader 5 终端在发 HTTP 请求时到底偷偷带了什么头,最省事的办法是拿 httpbin.org 当镜子——你发过去什么,它原样回什么。在 Experts/Connexus/Test/ 下建一个 TestHeader.mq5,先发一个不带任何自定义头的 POST,看回显里的 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 等系统信息,另外还有 AWS 的 X-Amzn-Trace-Id(例如 Root=1-66feb3d9-50de44d019af8b0c1058436b)。其中 Content-Length=0 印证了咱们没发 body;那个 Trace-Id 大概率是平台用来做请求诊断的。 头里不能有两个同名键,所以自定义时会直接覆盖默认值,而不是追加。比如把 Content-Type 改成 application/json、User-Agent 改成 Connexus/1.0 (MetaTrader 5 Terminal),拼进 headers_send 字符串并用 \n 分隔,再跑一次就能在回显里看到新值顶掉了旧的。 下面这段是最小可跑的裸请求示例,注意 WebRequest 的超时设的 5000 毫秒,返回体直接用 CharArrayToString 打印:

MQL5 / C++
class="macro">#include <Connexus2/Data/Json.mqh>
class="macro">#include <Connexus2/URL/URL.mqh>
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   class=class="str">"cmt">//--- URL
   CURL url;
   url.Parse("https:class=class="str">"cmt">//httpbin.org");
   url.Path("post");

   class=class="str">"cmt">//--- Data to be sent
   class="type">class="kw">string method = "POST";
   class="type">char body_send[];
   class="type">class="kw">string headers_send;

   class=class="str">"cmt">//--- Data that will be received
   class="type">char body_receive[];
   class="type">class="kw">string headers_receive;

   class=class="str">"cmt">//--- Send request
   class="type">int status_code = WebRequest(method,url.FullUrl(),headers_send,class="num">5000,body_send,body_receive,headers_receive);

   class=class="str">"cmt">//--- Show response
   Print("Respose: ",CharArrayToString(body_receive));
   class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

正文

<span class="comment">//Expert initialization function&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>

<span class="comment">//+------------------------------------------------------------------+</span> <span class="keyword">int</span> <span class="functions">OnInit</span>() &nbsp;&nbsp;{ &nbsp;&nbsp; <span class="comment">//--- URL</span> &nbsp;&nbsp; CURL url; &nbsp;&nbsp; url.Parse(<span class="string">"https://httpbin.org"</span>); &nbsp;&nbsp; url.Path(<span class="string">"post"</span>); &nbsp;&nbsp; &nbsp;&nbsp; <span class="comment">//--- Data to be sent</span> &nbsp;&nbsp; <span class="keyword">string</span> method = <span class="string">"POST"</span>; &nbsp;&nbsp; <span class="keyword">char</span> body_send[]; &nbsp;&nbsp; &nbsp;&nbsp; <span class="comment">//--- Headers that will be sent separated by "\n"</span> &nbsp;&nbsp; <span class="keyword">string</span> headers_send = <span class="string">"User-Agent: Connexus/1.0 (MetaTrader 5 Terminal)\nContent-Type: application/json"</span>; &nbsp;&nbsp; &nbsp;&nbsp; <span class="comment">//--- Data that will be received</span> &nbsp;&nbsp; <span class="keyword">char</span> body_receive[]; &nbsp;&nbsp; <span class="keyword">string</span> headers_receive; &nbsp;&nbsp; &nbsp;&nbsp; <span class="comment">//--- Send request</span> &nbsp;&nbsp; <span class="keywo

「搭一个存 HTTP 头部的类骨架」

在 MT5 的 Includes/Connexus 目录下新建 Headers 文件夹,里面放 HttpHeaders.mqh,这套目录结构能让后续多个 EA 共用同一套请求头逻辑,不用每次重写。 头部数据用 JSON 对象托管最省事:键是头部名、值是头部内容。类里声明一个 m_headers 实例,初始化即空 JSON,后面所有增删查都围绕它转。 先列清楚这个类要暴露的方法:Add(key,value) 新增或覆盖、Get(key) 取值、Remove(key) 删除、Has(key) 判断存在、Clear() 清空、Count() 计数,再加两个核心的 Serialize() 和 Parse(string)。 下面这段是类的空壳,只挂了构造和析构,注释里标了它专门管请求头的组织与存储。开 MT5 照这个建文件,编译能过就说明目录和类声明没写错。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                 Header.mqh |
class=class="str">"cmt">//|                                                  Copyright class="num">2024, MetaQuotes Ltd. |
class=class="str">"cmt">//|                                                       [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2023, MetaQuotes Ltd."
class="macro">#class="kw">property link      "[MQL5官方文档]
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| class : CHttpHeader                                                      |
class=class="str">"cmt">//|                                                                          |
class=class="str">"cmt">//| [PROPERTY]                                                               |
class=class="str">"cmt">//| Name      : CHttpHeader                                                  |
class=class="str">"cmt">//| Heritage  : No heritage                                                  |
class=class="str">"cmt">//| Description : Responsible for organizing and storing the headers         |
class=class="str">"cmt">//|               of a request.                                              |
class=class="str">"cmt">//|                                                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CHttpHeader
  {
class="kw">public:
                        CHttpHeader(class="type">void);
                       ~CHttpHeader(class="type">void);
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Constructor                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ 请求头容器的空壳与 JSON 依赖

在 MT5 里做 REST 请求封装时,CHttpHeader 这个类当前只是个空架子:构造和析构函数体均为空,没有实际的头部写入或解析逻辑。 它内部只持有一个私有成员 CJson m_headers,说明设计意图是把请求头以键值对形式塞进 JSON 对象来管理,而非用裸字符串数组。 代码里通过 #include "../Data/Json.mqh" 引入了 CJson 类,这意味着你编译前必须保证相对路径下有这个文件,否则会直接报找不到头文件。 开 MT5 验证时,可先新建一个 EA,把这段类声明贴进去并补上 Json.mqh 的本地路径,看编译器是否因缺失依赖而报错——这是排查请求模块能否跑起来的第一关。

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

请求头对象的封装与接口

在 MT5 里做 REST 请求时,把 HTTP 头信息从字符串拼凑改成结构化对象,能少踩很多坑。下面这个类用私有成员 CJson m_headers 承载所有键值对,对外只暴露增删查的轻量接口。 Add(string key, string value) 负责写入或覆盖某个头;Get(string key) 按名取值,取不到返回空串;Has(string key) 用布尔值告诉你某个头是否存在。Remove 与 Clear 分别删单条和清空,Count 回传当前头数量——这几个方法足够覆盖绝大多数鉴权头(如 Authorization、Content-Type)的动态维护。 构造函数 CHttpHeader::CHttpHeader(void) 体为空,说明初始化成本极低,直接在 EA 或脚本里声明即用。外汇与贵金属行情接口调用受网络与平台限制,实盘前请在策略测试器或 demo 环境验证头字段是否被网关正确转发。

MQL5 / C++
class=class="str">"cmt">//| [PROPERTY]                                                                 | //| Name     : CHttpHeader                                                      | //| Heritage : No heritage                                                      | //| Description : Responsible for organizing and storing the headers | //|              of a request.                                                  | //|                                                                            | //+------------------------------------------------------------------+
class CHttpHeader
  {
class="kw">private:
  CJson                m_headers;
class="kw">public:
                     CHttpHeader(class="type">void);
                    ~CHttpHeader(class="type">void);
  class=class="str">"cmt">//--- Functions to manage headers
  class="type">void                Add(class="type">class="kw">string key, class="type">class="kw">string value);     class=class="str">"cmt">// Adds a new header to the HTTP request or updates it if it already exists
  class="type">class="kw">string              Get(class="type">class="kw">string key);                   class=class="str">"cmt">// Returns the value of a specific header, given its name.
  class="type">void                Remove(class="type">class="kw">string key);                class=class="str">"cmt">// Removes a specific header.
  class="type">bool                Has(class="type">class="kw">string key);                   class=class="str">"cmt">// Checks whether a header with the specified key is present.
  class="type">void                Clear(class="type">void);                       class=class="str">"cmt">// Removes all headers from the request.
  class="type">int                 Count(class="type">void);                       class=class="str">"cmt">// Returns the number of headers.
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Constructor                                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
CHttpHeader::CHttpHeader(class="type">void)
  {
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
让小布替你核对头字段
这些诊断小布盯盘的AIGC已内置,打开对应品种页即可看到请求头拼装是否合规的提示,把重复劳动交给小布,你专注决策。

常见问题

多数API会拒收或返回默认格式,常见为401未授权、400错请求或HTML而非JSON,具体看服务端策略。
GET通常无请求体,头多用于认证与缓存;POST/PUT常需Content-Type与正文配套,否则服务端可能拒解析。
有。若 broker 或中间层缓存了旧响应,可能让行情或信号接口返回滞后数据,倾向显式控制或禁用缓存。
目前小布提供头字段合规诊断与示例片段参考,完整HttpHeaders类仍需在MQL5编辑器中落地,外汇贵金属属高风险,请自测后再接实盘。
概率上不安全,易被反编译提取,倾向通过加密配置或运行时注入,并限制token权限范围。