Connexus助手(第五部分):HTTP方法和状态码·综合运用
◍ HTTP 5xx 状态码与封装类设计
在 MT5 通过 WebRequest 对接外部行情或信号服务时,服务端返回 5xx 表示网关或服务器侧异常。常见的高位状态码包括 504 网关超时、505 协议版本不支持、506 协商变体、507 存储不足、508 环路检测、510 未扩展、511 网络认证要求,这些数字直接对应枚举值,可用于判断请求失败的性质。 下面这段类把状态码收进一个对象里,避免散落各处用裸 int 比较。私有成员 m_status 存当前状态,公有接口提供 int 与枚举两种赋值重载,以及 Get 取枚举、GetMessage 取描述文本。 构造与析构目前为空实现,说明该类只做轻量状态容器,不持有连接资源。实盘调用 WebRequest 后,把返回码喂给 CHttpStatusCodes,就能在 EA 日志里统一输出人类可读的失败原因,而不是一堆看不懂的数字。
HTTP_STATUS_GATEWAY_TIMEOUT = class="num">504, HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = class="num">505, HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = class="num">506, HTTP_STATUS_INSUFFICIENT_STORAGE = class="num">507, HTTP_STATUS_LOOP_DETECTED = class="num">508, HTTP_STATUS_NOT_EXTENDED = class="num">510, HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = class="num">511 }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| class : CHttpStatusCodes | class=class="str">"cmt">//| | class=class="str">"cmt">//| [PROPERTY] | class=class="str">"cmt">//| Name : CHttpStatusCodes | class=class="str">"cmt">//| Heritage : No heritage | class=class="str">"cmt">//| Description : Saved http status code. | class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CHttpStatusCodes { class="kw">private: ENUM_HTTP_STATUS m_status; class=class="str">"cmt">// Stores the status used class="kw">public: CHttpStatusCodes(class="type">void); ~CHttpStatusCodes(class="type">void); class=class="str">"cmt">//--- Set class="type">void class="kw">operator=(class="type">int status); class="type">void class="kw">operator=(ENUM_HTTP_STATUS status); class="type">void Set(ENUM_HTTP_STATUS status); class=class="str">"cmt">//--- Get ENUM_HTTP_STATUS Get(class="type">void); class="type">class="kw">string GetMessage(class="type">void); }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Destructor |
HTTP 状态封装类的赋值与取数逻辑
在 MT5 里做 WebRequest 调用外部行情或信号接口时,返回码的处理最好收口到一个类里。下面这段 CHttpStatusCodes 的实现,把整数和枚举两种状态来源都接住了,避免散落在 EA 各处做强制转换。 析构函数 CHttpStatusCodes::~CHttpStatusCodes(void) 是空的,说明这个类不持有需要手动释放的资源,轻量可直接栈上用。两个重载的 operator= 分别吃 int 和 ENUM_HTTP_STATUS:前者把整型先强转成枚举再存进 m_status,后者直接赋值,写代码时无论拿到的是 WebRequest 的原始 int 还是自己定义的枚举都能一句搞定。 Set(ENUM_HTTP_STATUS status) 与 Get(void) 是一对最朴素的存取器,Get 直接 return m_status,没有做越界校验——这意味着如果你塞了一个枚举外的值进去,取出来也不会报错,调试时容易踩坑。 GetMessage(void) 用 switch 把 m_status 映射成可读字符串。目前已覆盖的码里,HTTP_STATUS_URL_NOT_ALLOWED 对应“URL 未加入终端白名单”,HTTP_STATUS_OK 返回“OK”,HTTP_STATUS_PARTIAL_CONTENT 返回“Partial Content”等。注意 switch 在原文中列到 HTTP_STATUS_MULTIPLE_CHOICES 就断了,说明这个类在截取片段时尚未写完所有 3xx~5xx 分支,实盘复制前需补齐全量枚举映射,否则未知状态会落到默认返回空串。 外汇与贵金属行情接口调用受网络与经纪商限制,白名单漏配会直接触发 URL_NOT_ALLOWED,这类错误概率不低,建议上线前在策略测试器外先用脚本跑一次连通性。
CHttpStatusCodes::~CHttpStatusCodes(class="type">void) { } class="type">void CHttpStatusCodes::class="kw">operator=(class="type">int status) { m_status = (ENUM_HTTP_STATUS)status; } class="type">void CHttpStatusCodes::class="kw">operator=(ENUM_HTTP_STATUS status) { m_status = status; } class="type">void CHttpStatusCodes::Set(ENUM_HTTP_STATUS status) { m_status = status; } ENUM_HTTP_STATUS CHttpStatusCodes::Get(class="type">void) { class="kw">return(m_status); } class="type">class="kw">string CHttpStatusCodes::GetMessage(class="type">void) { class="kw">switch(m_status) { case HTTP_STATUS_URL_NOT_ALLOWED: class="kw">return "The URL was not added to the list of allowed URLs in the terminal"; case HTTP_STATUS_URL_NOT_DEFINED: class="kw">return "URL was not defined in the request"; case HTTP_STATUS_METHOD_NOT_DEFINED: class="kw">return "Method was not defined in the request"; case HTTP_STATUS_CONTINUE: class="kw">return "Continue"; case HTTP_STATUS_SWITCHING_PROTOCOLS: class="kw">return "Switching Protocols"; case HTTP_STATUS_PROCESSING: class="kw">return "Processing"; case HTTP_STATUS_EARLY_HINTS: class="kw">return "Early Hints"; case HTTP_STATUS_OK: class="kw">return "OK"; case HTTP_STATUS_CREATED: class="kw">return "Created"; case HTTP_STATUS_ACCEPTED: class="kw">return "Accepted"; case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION: class="kw">return "Non-Authoritative Information"; case HTTP_STATUS_NO_CONTENT: class="kw">return "No Content"; case HTTP_STATUS_RESET_CONTENT: class="kw">return "Reset Content"; case HTTP_STATUS_PARTIAL_CONTENT: class="kw">return "Partial Content"; case HTTP_STATUS_MULTI_STATUS: class="kw">return "Multi-Status"; case HTTP_STATUS_ALREADY_REPORTED: class="kw">return "Already Reported"; case HTTP_STATUS_MULTIPLE_CHOICES:
「HTTP 状态码的字符化映射」
在 MT5 的 WebRequest 封装函数里,把枚举型状态码转成可读字符串,是排查接口联通性的第一步。下面这段 switch 分支覆盖了从 3xx 重定向到 4xx 客户端错误的主要情形,直接 return 对应英文短语,方便在日志里肉眼定位。 例如 HTTP_STATUS_MOVED_PERMANENTLY 返回 "Moved Permanently",HTTP_STATUS_NOT_FOUND 返回 "Not Found",HTTP_STATUS_REQUEST_TIMEOUT 返回 "Request Timeout"。实盘调用第三方行情或信号接口时,若日志频繁出现 "Forbidden" 或 "Unauthorized",大概率不是策略问题,而是密钥或 IP 白名单配置失效。 外汇与贵金属接口调用受网络与平台限制,高风险且可能因 broker 策略中断;建议把这段映射原样塞进 EA 的调试模块,开 MT5 跑一次模拟请求验证输出。
class="kw">return "Multiple Choices"; case HTTP_STATUS_MOVED_PERMANENTLY: class="kw">return "Moved Permanently"; case HTTP_STATUS_FOUND: class="kw">return "Found"; case HTTP_STATUS_SEE_OTHER: class="kw">return "See Other"; case HTTP_STATUS_NOT_MODIFIED: class="kw">return "Not Modified"; case HTTP_STATUS_USE_PROXY: class="kw">return "Use Proxy"; case HTTP_STATUS_SWITCH_PROXY: class="kw">return "Switch Proxy"; case HTTP_STATUS_TEMPORARY_REDIRECT: class="kw">return "Temporary Redirect"; case HTTP_STATUS_PERMANENT_REDIRECT: class="kw">return "Permanent Redirect"; case HTTP_STATUS_BAD_REQUEST: class="kw">return "Bad Request"; case HTTP_STATUS_UNAUTHORIZED: class="kw">return "Unauthorized"; case HTTP_STATUS_PAYMENT_REQUIRED: class="kw">return "Payment Required"; case HTTP_STATUS_FORBIDDEN: class="kw">return "Forbidden"; case HTTP_STATUS_NOT_FOUND: class="kw">return "Not Found"; case HTTP_STATUS_METHOD_NOT_ALLOWED: class="kw">return "Method Not Allowed"; case HTTP_STATUS_NOT_ACCEPTABLE: class="kw">return "Not Acceptable"; case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED: class="kw">return "Proxy Authentication Required"; case HTTP_STATUS_REQUEST_TIMEOUT: class="kw">return "Request Timeout"; case HTTP_STATUS_CONFLICT: class="kw">return "Conflict"; case HTTP_STATUS_GONE: class="kw">return "Gone"; case HTTP_STATUS_LENGTH_REQUIRED: class="kw">return "Length Required"; case HTTP_STATUS_PRECONDITION_FAILED: class="kw">return "Precondition Failed"; case HTTP_STATUS_PAYLOAD_TOO_LARGE: class="kw">return "Payload Too Large"; case HTTP_STATUS_URI_TOO_LONG: class="kw">return "URI Too Long"; case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE: class="kw">return "Unsupported Media Type"; case HTTP_STATUS_RANGE_NOT_SATISFIABLE: class="kw">return "Range Not Satisfiable"; case HTTP_STATUS_EXPECTATION_FAILED:
◍ HTTP 状态枚举的尾部映射
这段 switch 收口的是 4xx 与 5xx 区间里偏冷门的状态码,从 421 Misdirected Request 一直铺到 511 Network Authentication Required,每个 case 直接回吐英文短语,方便 EA 在日志里原样打印。 default 分支兜底返回 Unknown HTTP Status,意味着若经纪商网关回了非标准码(比如某些 CDN 夹层返回的 520),你的诊断函数不会崩,但也不会给你更多信息。 实际跑 MT5 时,这类映射常出现在 WebRequest 封装类里;若你发现日志频繁出现 Too Many Requests,大概率是对方 REST 接口限频,外汇/贵金属行情接口在高波动期可能触发,属正常风控,需降低轮询频率。
class="kw">return "Expectation Failed"; case HTTP_STATUS_MISDIRECTED_REQUEST: class="kw">return "Misdirected Request"; case HTTP_STATUS_UNPROCESSABLE_ENTITY: class="kw">return "Unprocessable Entity"; case HTTP_STATUS_LOCKED: class="kw">return "Locked"; case HTTP_STATUS_FAILED_DEPENDENCY: class="kw">return "Failed Dependency"; case HTTP_STATUS_TOO_EARLY: class="kw">return "Too Early"; case HTTP_STATUS_UPGRADE_REQUIRED: class="kw">return "Upgrade Required"; case HTTP_STATUS_PRECONDITION_REQUIRED: class="kw">return "Precondition Required"; case HTTP_STATUS_TOO_MANY_REQUESTS: class="kw">return "Too Many Requests"; case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: class="kw">return "Request Header Fields Too Large"; case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: class="kw">return "Unavailable For Legal Reasons"; case HTTP_STATUS_INTERNAL_SERVER_ERROR: class="kw">return "Internal Server Error"; case HTTP_STATUS_NOT_IMPLEMENTED: class="kw">return "Not Implemented"; case HTTP_STATUS_BAD_GATEWAY: class="kw">return "Bad Gateway"; case HTTP_STATUS_SERVICE_UNAVAILABLE: class="kw">return "Service Unavailable"; case HTTP_STATUS_GATEWAY_TIMEOUT: class="kw">return "Gateway Timeout"; case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED: class="kw">return "HTTP Version Not Supported"; case HTTP_STATUS_VARIANT_ALSO_NEGOTIATES: class="kw">return "Variant Also Negotiates"; case HTTP_STATUS_INSUFFICIENT_STORAGE: class="kw">return "Insufficient Storage"; case HTTP_STATUS_LOOP_DETECTED: class="kw">return "Loop Detected"; case HTTP_STATUS_NOT_EXTENDED: class="kw">return "Not Extended"; case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED: class="kw">return "Network Authentication Required"; class="kw">default: class="kw">return "Unknown HTTP Status"; } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| class : CHttpStatusCodes |
把 HTTP 状态码收进一个类里判组
在 MT5 里用 WebRequest 拉外盘报价或新闻流时,返回的状态码决定你是该重发、还是直接报错停策略。下面这个类把状态码存成成员变量,再用几个布尔方法按区间归类,省得每次都在 EA 里写一堆 if 判断。 类里 m_status 是 ENUM_HTTP_STATUS 类型,构造和析构都是空实现,重点在五个判组函数:IsInformational 覆盖 100–199,IsSuccess 覆盖 200–299,IsRedirection 覆盖 300–399,IsClientError 覆盖 400–499,IsServerError 覆盖 500–599。 实盘接数据接口时,若 IsSuccess 返回 false 且 IsServerError 为 true,说明券商或数据商后端可能挂了,策略应倾向暂停请求而不是频繁重试,外汇和贵金属行情中断期间滑点风险显著放大。
class=class="str">"cmt">//| | class=class="str">"cmt">//| [PROPERTY] | class=class="str">"cmt">//| Name : CHttpStatusCodes | class=class="str">"cmt">//| Heritage : No heritage | class=class="str">"cmt">//| Description : Saved http status code. | class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ class CHttpStatusCodes { class="kw">private: ENUM_HTTP_STATUS m_status; class=class="str">"cmt">// Stores the status used class="kw">public: CHttpStatusCodes(class="type">void); ~CHttpStatusCodes(class="type">void); class=class="str">"cmt">//--- Check which group the code is in class="type">bool IsInformational(class="type">void); class=class="str">"cmt">// Checks if the status code is in the informational response range(class="num">100 - class="num">199) class="type">bool IsSuccess(class="type">void); class=class="str">"cmt">// Check if the status code is in the success range(class="num">200 - class="num">299) class="type">bool IsRedirection(class="type">void); class=class="str">"cmt">// Check if the status code is in the redirect range(class="num">300 - class="num">399) class="type">bool IsClientError(class="type">void); class=class="str">"cmt">// Checks if the status code is in the client error range(class="num">400 - class="num">499) class="type">bool IsServerError(class="type">void); class=class="str">"cmt">// Check if the status code is in the server error range(class="num">500 - class="num">599) }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Constructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+
「HTTP 状态码分类的析构与区间判定」
在 MT5 里封装 HTTP 响应处理时,CHttpStatusCodes 类的析构函数留空即可,因为该类通常只持有 m_status 整型成员,不申请堆内存,不需要手动释放资源。 真正的重点是五个布尔方法,把 m_status 按 RFC 7231 的区间直接映射成语义类别:100–199 是信息响应,200–299 是成功,300–399 是重定向,400–499 是客户端错误,500–599 是服务端错误。 这些判定没有复杂逻辑,就是边界比较。你在写 EA 调用 WebRequest 做行情中转或 AIGC 信号拉取时,用 IsSuccess() 过滤掉非 2xx 响应,能避免把 404 或 500 的空包当有效数据解析。 下面这段是类的析构与判定实现,逐行看:析构函数体为空;四个 Is* 方法均用 m_status 与硬编码上下界做 && 比较后 return。
class=class="str">"cmt">//| Destructor | class=class="str">"cmt">//+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(class="type">void) { } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Checks if the status code is in the informational response | class=class="str">"cmt">//| range(class="num">100 - class="num">199) | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CHttpStatusCodes::IsInformational(class="type">void) { class="kw">return(m_status >= class="num">100 && m_status <= class="num">199); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check if the status code is in the success range(class="num">200 - class="num">299) | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CHttpStatusCodes::IsSuccess(class="type">void) { class="kw">return(m_status >= class="num">200 && m_status <= class="num">299); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check if the status code is in the redirect range(class="num">300 - class="num">399) | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CHttpStatusCodes::IsRedirection(class="type">void) { class="kw">return(m_status >= class="num">300 && m_status <= class="num">399); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Checks if the status code is in the client error range | class=class="str">"cmt">//| (class="num">400 - class="num">499) | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CHttpStatusCodes::IsClientError(class="type">void) { class="kw">return(m_status >= class="num">400 && m_status <= class="num">499); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check if the status code is in the server error range(class="num">500 - class="num">599) | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CHttpStatusCodes::IsServerError(class="type">void) { class="kw">return(m_status >= class="num">500 && m_status <= class="num">599); } class=class="str">"cmt">//+------------------------------------------------------------------+
◍ 别急着下结论
这套 Connexus 辅助类目前只拆出了 CQueryParam、CHttpHeader、CHttpBody 三个独立处理单元,都依赖 CJson 但没有互相继承,彼此还没接成完整请求链路。也就是说,现在能单独拼出参数、头、体,却还发不出去一个真实 HTTP 调用。 方法和状态码是客户端—服务器通信的两块地基:200 代表通路正常,4xx 是客户端侧问题,5xx 是服务端崩了。读懂这些返回码,错误就不再是终止信号,而是重试或调参的入口。 下一篇才会把请求和响应类接起来,让上面三个类真正跑通。外汇与贵金属 API 对接本身高风险,未连线的代码直接上实盘等于裸奔,先在本机 MT5 里编译附件里的 24.99 KB ZIP 验证类结构再说。