Connexus中的正文(第四部分):添加HTTP请求正文·综合运用
📘

Connexus中的正文(第四部分):添加HTTP请求正文·综合运用

第 3/3 篇

◍ HTTP 请求体的字节与 JSON 转换接口

在 MT5 里做 REST 调用时,请求体往往既要能吃二进制,也要能直接吐 JSON。下面这组 CHttpBody 的成员函数把这件事拆得很干净:二进制用 char 数组承载,文本靠 codepage 控制编码,结构化数据则交给 CJson 反序列化。 AddBinary 用 ArrayCopy 把外部 data[] 整段拷进 m_body;Clear 调 ArrayFree 释放数组,避免重复请求时旧数据滞留。GetAsString 通过 CharArrayToString(m_body,0,WHOLE_ARRAY,m_codepage) 把字节流按指定代码页转成字符串,WHOLE_ARRAY 表示从 0 下标一直读到数组末尾。 GetAsJson 先取字符串再 json.Deserialize,若 body 里不是合法 JSON 会返回空对象,调用方得自己判空。GetAsBinary 反向用 ArrayCopy 把 m_body 拷出来,GetSize 返回 ArraySize(m_body) 即字节数——这是算 Content-Length 头时的直接依据。 SetCodePage 允许在发送前改 m_codepage,比如从默认 CP_ACP 切到 UTF-8(65001)。外汇与贵金属接口多要求 UTF-8,编码设错可能让中文 symbol 名或参数字符串乱码,进而被服务端拒。

MQL5 / C++
class="type">void CHttpBody::AddBinary(class="type">char &data[])
  {
   ArrayCopy(m_body,data);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Remove all body content                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CHttpBody::Clear(class="type">void)
  {
   ArrayFree(m_body);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Returns the request body as a class="type">class="kw">string                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string CHttpBody::GetAsString(class="type">void)
  {
   class="kw">return(CharArrayToString(m_body,class="num">0,WHOLE_ARRAY,m_codepage));
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Converts the request body into a JSON object, useful when the    |
class=class="str">"cmt">//| body contains structured data                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
CJson CHttpBody::GetAsJson(class="type">void)
  {
   CJson json;
   json.Deserialize(this.GetAsString());
   class="kw">return(json);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Returns the body as an array of bytes, useful for working with   |
class=class="str">"cmt">//| binary data                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CHttpBody::GetAsBinary(class="type">char &body[])
  {
   ArrayCopy(body,m_body);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Returns the size of the request body, usually in bytes           |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int CHttpBody::GetSize(class="type">void)
  {
   class="kw">return(ArraySize(m_body));
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Returns the defined codepage                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">uint CHttpBody::GetCodePage(class="type">void)
  {
   class="kw">return(m_codepage);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Defines the codepage to be used                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CHttpBody::SetCodePage(class="type">uint codepage)
  {
   m_codepage = codepage;
  }

「把下单参数塞进 POST 正文跑通」

继续验证 CHttpBody 类的实际表现,仍用 TestBody.mq5 这个文件。这次我们把一个 JSON 对象挂到 POST 请求正文里,字段覆盖 type、symbol、price、volume、tp、sl 六类下单要素。 先建 CJson 对象并逐项赋值,再交给 CHttpBody 实例的 AddJson 方法收纳。最后调 GetAsBinary 转成 char 数组,WebRequest 才能发出去。 回显里 "data" 字段带回了完整 JSON 字符串,Content-Length 显示 103 字节,说明 httpbin.org 服务端确实按 application/json 收下了正文。外汇与贵金属杠杆高,这类接口若接实盘信号须自行校验延迟与断连风险。 若只想发纯文本,把字符串直接塞 CHttpBody、头部改 text/plain 即可,上一轮已演示过。库完工后这串手动转换会隐藏掉,现阶段开发期还得自己写。

MQL5 / C++
{
  "type": "BUY",
  "symbol": "EURUSD",
  "price": class="num">1.09223
  "volume": class="num">0.01
  "tp": class="num">1.09233
  "sl": class="num">1.09213
}
CJson body_json;
body_json["type"] = "BUY";
body_json["symbol"] = "EURUSD";
body_json["price"] = class="num">1.09223;
body_json["volume"] = class="num">0.01;
body_json["tp"] = class="num">1.09233;
body_json["sl"] = class="num">1.09213;
CHttpBody body;
body.AddJson(body_json);
class=class="str">"cmt">//--- Body in class="type">char array
class="type">char body_send[];
body.GetAsBinary(body_send);
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";
  CJson body_json;
  body_json["type"] = "BUY";
  body_json["symbol"] = "EURUSD";
  body_json["price"] = class="num">1.09223;
  body_json["volume"] = class="num">0.01;
  body_json["tp"] = class="num">1.09233;
  body_json["sl"] = class="num">1.09213;
  CHttpBody body;
  body.AddJson(body_json);
  
  class=class="str">"cmt">//--- Body in class="type">char array
  class="type">char body_send[];
  body.GetAsBinary(body_send);
  
  class=class="str">"cmt">//--- Headers that will be sent separated by "\n"
  CHttpHeader headers_send;
  headers_send.Add("User-Agent","Connexus/class="num">1.0 (MetaTrader class="num">5 Terminal)");
  headers_send.Add("Content-Type","application/json");
  
  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.Serialize(),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">//+------------------------------------------------------------------+
Respose: {
  "args": {},
  "data": "{\"type\":\"BUY\",\"symbol\":\"EURUSD\",\"price\":class="num">1.09223000,\"volume\":class="num">0.01000000,\"tp\":class="num">1.09233000,\"sl\":class="num">1.09213000}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "pt,en;q=class="num">0.5",
    "Content-Length": "class="num">103",
    "Content-Type": "application/json",
    "Host": "httpbin.org",
    "User-Agent": "Connexus/class="num">1.0 (MetaTrader class="num">5 Terminal)",

用 WebRequest 把 EURUSD 信号推到外部接口

想把 MT5 里的下单意图实时丢给外部系统,关键在 WebRequest 的 POST 封装。上面这段响应体是个真实结构样例:symbol 为 EURUSD,type 为 BUY,volume 仅 0.01 手,price 1.09223,sl 1.09213,tp 1.09233,整体是 1 点止损、1 点止盈的极微仓试探,外汇和贵金属这类品种杠杆高,实盘跑这种参数前务必先在策略测试器验通道稳定性。 代码里 OnInit 直接拼了 https://httpbin.org 的 post 路径,用 CHttpBody 塞了 'My simple text' 做最小载荷,Header 里硬写了 User-Agent 和 Content-Type。注意 WebRequest 的超时给的是 5000 毫秒,返回 status_code 后把 body_receive 转字符串 Print 出来,你复制去 MT5 编译,专家日志里就能看到 httpbin 回显的完整 JSON。 别把正态当圣经 回显里的 X-Amzn-Trace-Id 只是 httpbin 后端 AWS 链路标识,跟你策略胜负零相关;真要落地信号转发,得把 body.AddString 换成按 json 字段组包,否则外部服务大概率拒收。

MQL5 / C++
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";
   CHttpBody body;
   body.AddString("My simple text");
   
   class=class="str">"cmt">//--- Body in class="type">char array
   class="type">char body_send[];
   body.GetAsBinary(body_send);
   
   class=class="str">"cmt">//--- Headers that will be sent separated by "\n"
   CHttpHeader headers_send;
   headers_send.Add("User-Agent","Connexus/class="num">1.0 (MetaTrader class="num">5 Terminal)");
   headers_send.Add("Content-Type","text/plain");
   
   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.Serialize(),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);
  }

◍ 最后一句大实话

把正文塞进 HTTP 请求这件事,本质上就是选对格式再配好请求头:JSON 在 API 场景里用得最频,Connexus 的 CHttpBody 类已经把字节级格式化藏到底层,你只管填数据。 下一篇会拆 GET/POST/PUT/DELETE 和 200、404、500 这些状态码,但眼下你能做的,是打开 MT5 把那 19.59 KB 的 ZIP 里的 CHttpBody 跑一遍,确认 UTF-8 下中文不再乱码。 外汇与贵金属接口调用同样高风险,行情瞬变时请求超时或状态码异常都可能让你漏掉信号,先在模拟环境验证再上实盘。

常见问题

用字节与 JSON 转换接口把参数序列化后填入 WebRequest 的 body 字段,外发前先打印长度确认不为空。
优先检查 JSON 字段名是否与接收端一致,以及 Content-Type 是否设为 application/json,再查超时设置。
小布可接管 WebRequest 的拼包与发送,并在返回非 200 时给出错误摘要,你只需复核策略逻辑。
倾向用字节数组显式控制编码,避免终端默认编码导致服务端解析乱码,尤其含中文注释时。
可能服务端要特定字段顺序或多余空格,用十六进制dump正文比对线上示例最直观。