HTTP和Connexus(第2部分):理解HTTP架构和库设计·进阶篇
(2/3)· 搞懂URL拆解与请求三件套,才能把WebRequest的坑提前埋进类里
「从一条 URL 拆出可程序化的请求结构」
以一条典型行情接口地址为例:协议为 https,域名 www.example.com,端口 8080,路径 /market/symbols,查询参数 active=EURUSD&timeframe=h1。把这段拆开看,外汇 EURUSD 与周期 h1 都以键值对形式挂在问号之后,意味着行情请求本质是可被代码拼装的字符串。 在 MT5 上做 AIGC 式行情拉取时,硬编码地址很难复用。更稳的做法是把协议、域名、端口、路径、参数各自存为变量,由类方法动态拼接。这样切换黄金 XAUUSD 或切到 m5,只改参数不改结构。 下面这段是原文给出的地址示例,注意 & 在代码注释里写作 & 是 HTML 转义,MQL5 字符串里直接用 & 即可: [CODE] https:<span class="comment">//www.exemplo.com:8080/market/symbols?active=EURUSD&timeframe=h1</span> [/CODE] 构建 Connexus 库的第一层,就落在负责 URL 与查询参数操作的类上。先写能增删参数的方法,后面接行情接口时才不会每次手拼字符串、漏写端口。外汇与贵金属接口调用涉及实时网络请求,存在连接失败与数据延迟的高风险,参数拼错往往直接返回空响应。
https:<span class="comment">class=class="str">"cmt">//www.exemplo.com:class="num">8080/market/symbols?active=EURUSD&timeframe=h1</span>
◍ 用 CUrl 与 CJson 管住查询参数
做 MT5 下的 WebRequest 调用,最烦的是手工拼 query string。这一节先把底层骨架立起来:建一个 CUrl 类,专职拼基础地址、挂参数、输出完整 URL,不让散字符串在代码里乱飞。 参数管理另起一个 CJson 类。它干的事很具体——把原本挤在 URL 里的 ?a=1&b=2 这类查询串,转成结构化 JSON。这样后续增删字段不用正则去切字符串,直接按键值读写,出错概率低得多。 实际验证路径:在 MT5 里新建这两个类,随便喂一个 "symbol=EURUSD&tf=M15" 的参数字符串给 CJson,看它吐出的 JSON 对象是否字段齐全。外汇与贵金属行情接口调用本身属高风险操作,参数错一处就可能拿到空响应。
先搞清JSON长什么样
在MT5里用CJson类解析外部信号前,得先认得JSON这种结构。它是网页端传结构化数据最常用的轻量格式,本质就是一组被大括号{}包起来的键值对,键和值之间用冒号隔开,多对之间用逗号分开。 你可以把它和URL里的查询参数对照着看:?name=John&age=30 里 name 是键、John 是值,JSON不过是把这种关系用更规整的嵌套文本写出来,方便程序直接反序列化。 下面这段就是一个最直白的例子,三个键 name、age、city 各自带一个值,没有层级嵌套,适合先拿来做解析练习。
{
"name": "John",
"age": class="num">30,
"city": "New York"
}「用 CJson 把查询参数结构化」
在 MT5 里拼 REST 请求时,很多人直接手写 ?name=John&age=30 这种参数字符串。参数一多,拼接、改值、校验都很易错,可读性也差。
CJson 类的价值是把这些参数先收进一个结构化对象,再序列化成 JSON 塞进 URL 或请求体。组织、读取、验证都更干净,后续发送和接收数据也能复用同一套逻辑。
实际落地:开 MT5 新建 EA,include 进 CJson 相关头文件,先试着把 3 个字符串参数转成 JSON 文本,确认输出格式无误再接接口。外汇与贵金属接口调用涉及账户与行情风险,参数错配可能导致请求被拒或异常下单。
◍ 搭好 Connexus 的头文件骨架
在 MetaEditor 里先把目录层级建清楚,否则后面 include 路径会反复报错。具体做法是在 includes 下新建 Connexus 文件夹,其下再分 Data 与 URL 两个子目录。 Data 里放 Json.mqh(文末附带的 CJson 类),URL 里放 QueryParam.mqh 与 URL.mqh。CJson 的实现细节不用深究,接口很直白,重点是把物理路径对齐。 最终目录树应如下,少一个文件编译都会失败:
MQL5 |--- include |--- |--- Connexus |--- |--- |--- Data |--- |--- |--- |--- Json.mqh |--- |--- |--- URL |--- |--- |--- |--- QueryParam.mqh |--- |--- |--- |--- URL.mqh
封装查询参数的键值管理类
在 MT5 里拼 REST 请求前,先把零散的查询参数收拢到一个类里更稳妥。CQueryParam 内部挂了一个私有的 CJson 对象 m_query_param,所有参数以键值对形式存在这张表里,避免手动拼字符串时漏掉 & 或 =。 对外暴露的方法覆盖了增删查与序列化:AddParam 有两个重载,一个收 key/value 两个入参,另一个直接吃 key=value 形态的整串,遇到 = 才切分;AddParams 用字符串数组批量灌入,本质是对数组每项调一遍单参版 AddParam。 RemoveParam 按 key 摘掉某条;GetParam 按 key 返回值;HasParam 探一下 key 在不在;ParamSize 回传当前条目数。Parse 吃一整条 query 字符串,按 & 切参数、按 = 切键值后写进 m_query_param;Serialize 反向把表里内容拼回 key=value&... 形态,供 WebRequest 直接带出去。Clear 清空复位。 下面这段是类的骨架声明,注意头里要自己补 CJSON 的导入语句才能编译过。开 MT5 建个 include 试一下,先 AddParam("symbol","XAUUSD") 再 Serialize,应该得到 symbol=XAUUSD——外汇贵金属行情接口调用失败,多半是参数没序列化对,杠杆和高波动风险自己掂量。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| class : CQueryParam | class=class="str">"cmt">//| | class=class="str">"cmt">//| [PROPERTY] | class=class="str">"cmt">//| Name : CQueryParam | class=class="str">"cmt">//| Heritage : No heritage | class=class="str">"cmt">//| Description : Manages query parameters for HTTP requests | class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CQueryParam { class="kw">private: CJson m_query_param; class=class="str">"cmt">// Storage for query parameters class="kw">public: CQueryParam(class="type">void); ~CQueryParam(class="type">void); class=class="str">"cmt">//--- Functions to manage query parameters class="type">void AddParam(class="type">class="kw">string key, class="type">class="kw">string value); class=class="str">"cmt">// Add a key-value pair class="type">void AddParam(class="type">class="kw">string param); class=class="str">"cmt">// Add a single key-value parameter class="type">void AddParams(const class="type">class="kw">string ¶ms[]); class=class="str">"cmt">// Add multiple parameters class="type">void RemoveParam(const class="type">class="kw">string key); class=class="str">"cmt">// Remove a parameter by key class="type">class="kw">string GetParam(const class="type">class="kw">string key) const; class=class="str">"cmt">// Retrieve a parameter value by key