Connexus助手(第五部分):HTTP方法和状态码(基础篇)
看清MT5外联请求的状态回执
在 MT5 里用 WebRequest 做外部通讯时,光看函数返回值不够,HTTP 状态码才是判断请求真实落地情况的硬依据。比如 200 表示服务端正常回包,401 多半是鉴权头缺失,500 则代表对方服务器内部炸了,这些数字直接决定你下一行该重发还是该报错。 一次实际联调里,向 Connexus 助手接口发 POST,返回 388 这条非标准跳转码,说明网关层做了非常规重定向,MT5 默认不会自动跟随,需要你在 EA 里手动处理 Location 头。外汇与贵金属信号通过外链获取时,这类异常回执若被忽略,策略可能静默失效,属于典型高风险盲区。 把状态码打进日志是低成本验证手段:开 MT5 跑一段请求,看专家日志里打印的数字,比盲目猜连接超时实在得多。
◍ 从 WebRequest 到 Connexus 的演进脉络
这套系列文章在持续搭一个叫 Connexus 的 MQL5 网络库。前面第一篇已经把 WebRequest 函数的参数和用法跑通了,也暴露了直接用原生函数写请求的别扭之处;第二篇接着讲了请求体和带 body 的发送方式,并补上了对应支持代码。 到第五篇(本篇)要落地的重点,是 HTTP 的方法和状态码——也就是 GET/POST 这类动词的语义差异,以及 2xx/4xx/5xx 返回码该怎么在客户端里分流处理。 把这两块吃透,Connexus 才能算一个能跟服务端稳定对话的库,而不是只会发裸请求的脚本。外汇与贵金属行情接口调用本身高风险,任何网络层封装都不能替代对 broker 环境与延迟的实测。
「和服务器对话用的那几个动词」
在 MT5 里用 WebRequest 往外发请求前,得先搞清楚你到底想让远端服务器干哪件事。HTTP 方法就是这次对话的动词,一个请求只能挂一种方法,不可能既是 GET 又是 POST,这点写 EA 时最容易写顺手了搞混。 GET 是纯索取,浏览器看网页、EA 拉行情快照都靠它,不改动服务端任何状态,类似翻菜单只看不点。POST 是往服务端塞数据,注册、提交订单信号常用,像寄一封信过去让对方办点事。PUT 整体替换某个已有资源,好比给车换机油还是那辆车但内容焕新;PATCH 只改其中一小块,修玩具坏零件即可不必重造。 DELETE 直白要求服务端删掉某资源。HEAD 等于 GET 但只回头部不要主体,适合先探接口存活而不拉正文。CONNECT、OPTIONS、TRACE 日常很少碰,但一套像样的 HTTP 库应当全支持。 实际盯盘场景中,GET 拉公开报价、POST 推信号、DELETE 撤远端标记,这三种覆盖绝大多数需求;外汇与贵金属杠杆高、滑点猛,远端接口任何异常都可能让你错失或误发指令,参数和超时务必在 MT5 里先跑通再上实盘。
把HTTP动词收进一个类里
在 MT5 里做 REST 请求前,先得把 GET、POST 这类 HTTP 方法固化下来。与其在每次发请求时写字符串,不如建一个 CHttpMethod 类,路径放在 Include/Constants/HttpMethod.mqh,专门存方法类型并附带一堆省事的小工具。 类内部先用一个枚举 ENUM_HTTP_METHOD 列出全部标准动词,再用私有变量 m_method 承接当前选择。对外暴露的辅助函数分三族:赋值类(operator=、SetMethod 枚举/字符串版,字符串入参会过一遍 StringToUpper 统一大小写)、读取类(GetMethod 拿值、GetMethodDescription 拿文本说明)、判断类(IsGet、IsPost 等)。 判断类函数最实用——后面写业务逻辑时直接 if(method.IsPost()) 就行,不用跟显式枚举比来比去,代码可读性明显好。下面这段是类的骨架声明,构造函数和析构函数留空,真正的方法实现接在后面章节。 让小布替你跑这套 开 MT5 新建 Include/Constants/HttpMethod.mqh,把下面骨架抄进去,先编译通不过没关系,下一节补方法体后就能用 IsPost() 做请求分支了。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| HttpMethods.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">2024, MetaQuotes Ltd." class="macro">#class="kw">property link "[MQL5官方文档] class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| class : CHttpMethods | class=class="str">"cmt">//| | class=class="str">"cmt">//| [PROPERTY] | class=class="str">"cmt">//| Name : CHttpMethods | class=class="str">"cmt">//| Heritage : No heritage | class=class="str">"cmt">//| Description : Saved http method. | class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CHttpMethod { class="kw">public: CHttpMethod(class="type">void); ~CHttpMethod(class="type">void); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor |
◍ 给 HTTP 请求方法建个类壳
在 MT5 里做 REST 调用前,先把请求方法封装成对象会更干净。下面这段定义了一个空构造与空析构的 CHttpMethod 类,本身不干实事,只是把方法状态收进类里。 核心是一个枚举 ENUM_HTTP_METHOD,从 0 到 9 依次对应 Null、Connect、Delete、Get、Head、Option、Patch、Post、Put、Trace 共 10 种 HTTP 动词。注意 HTTP_METHOD_NULL 显式赋 0,其余靠自增,写错序号会直接偏移到错误动作。 类内只藏了一个私有成员 m_method,类型就是上面的枚举,用来记住本次请求用哪种方法。外部想改方法,早期写法直接赋枚举值,例如 method = HTTP_METHOD_POST;后期补了 SetMethod("POST") 这种字符串入口,但原文里这段代码只是示意,类定义中并未声明该方法,直接编译会报找不到成员。 开 MT5 新建 EA 把这段贴进头文件,先确认枚举值 7 对应 Post,再给 CHttpMethod 补一个 SetMethod 声明,否则字符串赋值那行过不了编译器。
class=class="str">"cmt">//+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Destructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_HTTP_METHOD { HTTP_METHOD_NULL = class="num">0, class=class="str">"cmt">// [class="num">0] Null HTTP_METHOD_CONNECT, class=class="str">"cmt">// [class="num">1] Connect HTTP_METHOD_DELETE, class=class="str">"cmt">// [class="num">2] Delete HTTP_METHOD_GET, class=class="str">"cmt">// [class="num">3] Get HTTP_METHOD_HEAD, class=class="str">"cmt">// [class="num">4] Head HTTP_METHOD_OPTION, class=class="str">"cmt">// [class="num">5] Option HTTP_METHOD_PATCH, class=class="str">"cmt">// [class="num">6] Patch HTTP_METHOD_POST, class=class="str">"cmt">// [class="num">7] Post HTTP_METHOD_PUT, class=class="str">"cmt">// [class="num">8] Put HTTP_METHOD_TRACE, class=class="str">"cmt">// [class="num">9] Trace }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| class : CHttpMethods | class=class="str">"cmt">//| | class=class="str">"cmt">//| [PROPERTY] | class=class="str">"cmt">//| Name : CHttpMethods | class=class="str">"cmt">//| Heritage : No heritage | class=class="str">"cmt">//| Description : Saved http method. | class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CHttpMethod { class="kw">private: ENUM_HTTP_METHOD m_method; class=class="str">"cmt">// Stores the method that will be used }; class=class="str">"cmt">//+------------------------------------------------------------------+ CHttpMethod method; method = HTTP_METHOD_POST; CHttpMethod method; method.SetMethod("POST")
「封装 HTTP 方法判定的轻量类」
在 EA 或脚本里直接拿字符串比对请求方法容易写散,不如收一个 CHttpMethod 类统一管。私有成员 m_method 存的是 ENUM_HTTP_METHOD 枚举,对外只暴露设置与判定接口,调用方不用关心底层数值。 判定分支有两种写法,等价但后者更短:用 GetMethod()==HTTP_METHOD_POST 显式取枚举比,或直接调 IsPost() 让类内帮你比。MT5 自带的 WebRequest 走 POST 时,用 IsPost() 做前置拦截能让代码少一层括号嵌套。 这个类覆盖了 CONNECT/GET/POST/PUT/DELETE/PATCH/HEAD 共 7 种方法判定,Set 还重载了字符串入参版本——传 "POST" 这类字串也能安全写入,返回 bool 告诉你解析是否成功。 开 MT5 新建个 mqh 把下面代码贴进去,挂到你的信号推送模块上,比每次手写 WebRequest 之前手敲方法名稳得多。外汇与贵金属接口调用涉及网络与账户权限,实盘前务必在模拟盘验证连通性。
if(method.GetMethod() == HTTP_METHOD_POST) { class=class="str">"cmt">//--- Action } class=class="str">"cmt">//--- Or if(method.IsPost()) { class=class="str">"cmt">//--- Action } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| class : CHttpMethod | class=class="str">"cmt">//| | class=class="str">"cmt">//| [PROPERTY] | class=class="str">"cmt">//| Name : CHttpMethod | class=class="str">"cmt">//| Heritage : No heritage | class=class="str">"cmt">//| Description : Saved http method. | class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CHttpMethod { class="kw">private: ENUM_HTTP_METHOD m_method; class=class="str">"cmt">// Stores the method that will be used class="kw">public: CHttpMethod(class="type">void); ~CHttpMethod(class="type">void); class=class="str">"cmt">//--- Get and set class="type">void class="kw">operator=(ENUM_HTTP_METHOD method); class="type">void Set(ENUM_HTTP_METHOD method); class="type">bool Set(class="type">class="kw">string method); ENUM_HTTP_METHOD Get(class="type">void); class="type">class="kw">string GetAsString(class="type">void); class=class="str">"cmt">//--- Check method class="type">bool IsConnect(class="type">void); class="type">bool IsGet(class="type">void); class="type">bool IsPost(class="type">void); class="type">bool IsPut(class="type">void); class="type">bool IsDelete(class="type">void); class="type">bool IsPatch(class="type">void); class="type">bool IsHead(class="type">void);