
Connexus助手(第五部分):HTTP方法和状态码
概述
本文是该系列文章的延续,我们将构建一个名为Connexus的库。在第一篇文章中,我们了解到WebRequest函数的基本工作原理,理解了其每个参数,并且还创建了一个示例代码,展示了该函数的使用及其困难之处。在上一篇文章中,我们了解到请求是如何工作的、请求体是什么,以及如何向服务器发送数据,最后我们还开发了对附有请求体的请求的支持。
在构建Connexus库的第五篇文章中,我们将探讨HTTP协议的一个重要方面:方法和状态码。了解每种HTTP动词的工作原理以及如何处理状态码,对于创建客户端和服务器之间可靠的交互至关重要。让我们开始吧!
HTTP方法
HTTP方法是我们要求服务器执行的操作。当您发起一个HTTP请求,比如访问一个页面或发送数据时,您实际上是在使用这些动词与服务器进行“交谈”。主要包括:
- GET:这是经典的“给我那个(资源)”。浏览器请求查看服务器上的某样东西,无论是页面、图片还是文件。它只是获取信息,而不改变任何东西。就像询问餐厅的菜单,只是为了看看有什么供应。
- POST:POST是那个输送包裹(资源)的人。这里,您正在向服务器发送数据。这在表单中很常见,比如当您在一个网站上注册时。可以想象成您在寄一封信:等待信到达目的地,并在那里做一些事情,例如完成注册。
- PUT:当您使用PUT时,基本上是在说:“把这里的东西换成这个新版本”。其用于更新现有的资源。就像给您的车换机油——还是同一辆车,但现在有了新的东西。
- DELETE:很直接,对吧?就是“把那个资源拿走。” 您要求服务器删除某样东西。再见,再也不见。
- PATCH:PATCH更加精细。它只改变资源的一部分。就像修理玩具的一个坏掉的部分——您不需要改变一切,只需要调整坏掉的部分。
- HEAD:这是GET,但没有主体。您只需要头部信息,而非主体。就像阅读一本书的标题而不翻开内容页面。
还有其他一些方法,例如CONNECT、OPTIONS和TRACE,但在开发人员的日常工作中很少使用。我在这里不会详细介绍每一种方法,但我希望这个库能够支持所有的HTTP方法。如果您想了解更多关于所有HTTP方法的信息,可以访问完整的协议文档,请点击此处。但相信我,在开发者的日常工作中,最常见的请求类型,如GET、POST和DELETE,足以应对大多数问题。
我想强调的是,每个请求只能使用一种方法,也就是说,一个请求不能同时是GET和POST类型。
创建CHttpMethod类
既然我们已经了解了每种HTTP方法的作用以及何时使用它们,那么让我们直接实现代码。我们将在Connexus中实现一个类,用于存储将用于发起请求的HTTP方法。这将是一个非常简单的类,无论您的编程水平如何,都能理解大部分内容。该类的目的仅仅是存储所使用的方法,但由于是在类中实现,我们会添加更多的功能,以便让Connexus库的最终用户尽可能轻松地使用。
让我们首先创建一个名为Constants的新文件夹,然后在其中创建一个名为CHttpMethod的新文件。最终路径将如下所示:Include/Constants/HttpMethod.mqh。在这个新文件中,我们将创建CHttpMethod类:
//+------------------------------------------------------------------+ //| HttpMethods.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpMethods | //| | //| [PROPERTY] | //| Name : CHttpMethods | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { public: CHttpMethod(void); ~CHttpMethod(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(void) { } //+------------------------------------------------------------------+
为了包含所有可能的HTTP方法,让我们创建一个枚举 ,该枚举将包含HTTP请求的所有可能方法。同时,让我们在类中添加一个类型为ENUM_HTTP_METHOD的新变量,命名为m_method:
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ enum ENUM_HTTP_METHOD { HTTP_METHOD_NULL = 0, // [0] Null HTTP_METHOD_CONNECT, // [1] Connect HTTP_METHOD_DELETE, // [2] Delete HTTP_METHOD_GET, // [3] Get HTTP_METHOD_HEAD, // [4] Head HTTP_METHOD_OPTION, // [5] Option HTTP_METHOD_PATCH, // [6] Patch HTTP_METHOD_POST, // [7] Post HTTP_METHOD_PUT, // [8] Put HTTP_METHOD_TRACE, // [9] Trace }; //+------------------------------------------------------------------+ //| class : CHttpMethods | //| | //| [PROPERTY] | //| Name : CHttpMethods | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { private: ENUM_HTTP_METHOD m_method; // Stores the method that will be used }; //+------------------------------------------------------------------+
既然已经有了用于存储的变量,接下来让我们创建一些辅助方法来定义和获取HTTP方法,此外还要重载=运算符以简化使用,其主要功能如下:
- 赋值运算符(operator=):允许您直接使用=运算符来定义HTTP方法。
- SetMethod(ENUM_HTTP_METHOD) 和SetMethod(string):通过枚举或字符串来定义HTTP方法。当参数为字符串类型时,会使用 StringToUpper()函数来正确格式化字符串。
- GetMethod() 和GetMethodDescription():获取HTTP方法及其文本描述。
- void operator=(ENUM_HTTP_METHOD method):这是一个重载操作,简单来说,它用于使用“=”运算符来定义HTTP方法。以下是该运算符在实际使用中的一个示例:
CHttpMethod method; method = HTTP_METHOD_POST;
- 验证函数(如 IsPost()、IsGet() 等):它们简化了方法的验证过程,使代码更具可读性和简洁性。以下是这些函数如何帮助我们的一个示例:
CHttpMethod method; method.SetMethod("POST") if(method.GetMethod() == HTTP_METHOD_POST) { //--- Action } //--- Or if(method.IsPost()) { //--- Action }
这样一来,我们就可以避免与显式方法比较。
//+------------------------------------------------------------------+ //| class : CHttpMethod | //| | //| [PROPERTY] | //| Name : CHttpMethod | //| Heritage : No heritage | //| Description : Saved http method. | //| | //+------------------------------------------------------------------+ class CHttpMethod { private: ENUM_HTTP_METHOD m_method; // Stores the method that will be used public: CHttpMethod(void); ~CHttpMethod(void); //--- Get and set void operator=(ENUM_HTTP_METHOD method); void Set(ENUM_HTTP_METHOD method); bool Set(string method); ENUM_HTTP_METHOD Get(void); string GetAsString(void); //--- Check method bool IsConnect(void); bool IsGet(void); bool IsPost(void); bool IsPut(void); bool IsDelete(void); bool IsPatch(void); bool IsHead(void); bool IsOption(void); bool IsTrace(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpMethod::CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpMethod::~CHttpMethod(void) { } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ void CHttpMethod::operator=(ENUM_HTTP_METHOD method) { m_method = method; } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ void CHttpMethod::Set(ENUM_HTTP_METHOD method) { m_method = method; } //+------------------------------------------------------------------+ //| Defines the http method | //+------------------------------------------------------------------+ bool CHttpMethod::Set(string method) { string method_upper = method; StringToUpper(method_upper); if(method_upper == "CONNECT") { m_method = HTTP_METHOD_CONNECT; return(true); } else if(method_upper == "DELETE") { m_method = HTTP_METHOD_DELETE; return(true); } else if(method_upper == "GET") { m_method = HTTP_METHOD_GET; return(true); } else if(method_upper == "HEAD") { m_method = HTTP_METHOD_HEAD; return(true); } else if(method_upper == "OPTIONS") { m_method = HTTP_METHOD_OPTION; return(true); } else if(method_upper == "PATCH") { m_method = HTTP_METHOD_PATCH; return(true); } else if(method_upper == "POST") { m_method = HTTP_METHOD_POST; return(true); } else if(method_upper == "PUT") { m_method = HTTP_METHOD_PUT; return(true); } else if(method_upper == "TRACE") { m_method = HTTP_METHOD_TRACE; return(true); } return(false); } //+------------------------------------------------------------------+ //| Get http method | //+------------------------------------------------------------------+ ENUM_HTTP_METHOD CHttpMethod::Get(void) { return(m_method); } //+------------------------------------------------------------------+ //| Get the description of the selected http method | //+------------------------------------------------------------------+ string CHttpMethod::GetAsString(void) { switch(m_method) { case HTTP_METHOD_NULL: return "NULL"; case HTTP_METHOD_CONNECT: return "CONNECT"; case HTTP_METHOD_DELETE: return "DELETE"; case HTTP_METHOD_GET: return "GET"; case HTTP_METHOD_HEAD: return "HEAD"; case HTTP_METHOD_OPTION: return "OPTIONS"; case HTTP_METHOD_PATCH: return "PATCH"; case HTTP_METHOD_POST: return "POST"; case HTTP_METHOD_PUT: return "PUT"; case HTTP_METHOD_TRACE: return "TRACE"; default: return "Unknown HTTP Method"; } } //+------------------------------------------------------------------+ //| Check if method is connect | //+------------------------------------------------------------------+ bool CHttpMethod::IsConnect(void) { return(m_method == HTTP_METHOD_CONNECT); } //+------------------------------------------------------------------+ //| Check if method is get | //+------------------------------------------------------------------+ bool CHttpMethod::IsGet(void) { return(m_method == HTTP_METHOD_GET); } //+------------------------------------------------------------------+ //| Check if method is post | //+------------------------------------------------------------------+ bool CHttpMethod::IsPost(void) { return(m_method == HTTP_METHOD_POST); } //+------------------------------------------------------------------+ //| Check if method is put | //+------------------------------------------------------------------+ bool CHttpMethod::IsPut(void) { return(m_method == HTTP_METHOD_PUT); } //+------------------------------------------------------------------+ //| Check if method is delete | //+------------------------------------------------------------------+ bool CHttpMethod::IsDelete(void) { return(m_method == HTTP_METHOD_DELETE); } //+------------------------------------------------------------------+ //| Check if method is patch | //+------------------------------------------------------------------+ bool CHttpMethod::IsPatch(void) { return(m_method == HTTP_METHOD_PATCH); } //+------------------------------------------------------------------+ //| Check if method is head | //+------------------------------------------------------------------+ bool CHttpMethod::IsHead(void) { return(m_method == HTTP_METHOD_HEAD); } //+------------------------------------------------------------------+ //| Check if method is option | //+------------------------------------------------------------------+ bool CHttpMethod::IsOption(void) { return(m_method == HTTP_METHOD_OPTION); } //+------------------------------------------------------------------+ //| Check if method is trace | //+------------------------------------------------------------------+ bool CHttpMethod::IsTrace(void) { return(m_method == HTTP_METHOD_TRACE); } //+------------------------------------------------------------------+
至此,我们已经完成了负责存储所使用的HTTP方法的类的实现。我们添加了一些辅助函数,以便在之后省去部分代码。接下来,让我们继续讨论下一个辅助类。
状态码
状态码,简单来说,就是数字。该数字已标准化,服务器在处理完请求后会将其发送给客户端。每个状态码都由三位数字组成,第一位数字表示状态所属的类别(1xx、2xx、3xx、4xx 和 5xx)。该状态码简单地告诉您请求的结果是什么,是成功完成、服务器端生成了错误,还是请求发送不正确。状态码有很多种。此数字的范围在100到599之间,它们被分为5个类别。要确定状态码属于哪个类别,只需识别它所在的数值范围即可,请查看包含这些数值的表格:
状态码范围 | 说明 |
---|---|
100-199 | 这类状态码不太常见。它们通常表示“正在处理,请稍候”之类的响应。这是服务器在告诉您,它正在处理您的请求,但尚未完成。 |
200-299 | 啊,这是我们最喜欢的响应!这就意味着一切顺利。最著名的就是200 OK — 表示“一切顺利”。您提出了请求,服务器也成功响应了。就这么简单。 |
300-399 | 服务器基本上是在告诉您:“哎呀,您走错地方了,去那儿吧。” 301 Moved Permanently表示永久重定向,而302 Found表示临时重定向——类似于“我正在修整,但您现在可以在这里找到它”。 |
400-499 | 这些是我们作为用户经常引起的典型错误。最广为人知的就是404 Not Found,当您请求的页面根本不存在时,就会出现这个错误。这就像您到达了一个地方,却发现想去的那栋建筑已经被拆除了。 |
500-599 | 现在,当问题出在另一侧时,责任就落在了服务器上。流性的500 Internal Server Error基本上就是服务器举手投降,说“这里出错了”。 |
状态码有多种可能,为了不让文章过于冗长,我不会一一列举。如果您想了解所有可能的值,请点击此处阅读,它详细解释了每个可能的状态码,如果你想深入了解HTTP协议,这篇文章值得一读。在开发人员的日常工作中,只会用到少数几个状态码,而且其中大部分在网络上并不常见。我将列出最常见的状态码:
1xx:信息性状态码
- 100Continue(继续):服务器已收到请求头,客户端可以继续发送请求体。
- 101Switching Protocols(切换协议):客户端请求更改协议,服务器已接受。
2xx:成功状态码
- 200OK:请求已成功。
- 201Created(已创建):请求已成功,并创建了新资源。- 204 No Content(无内容) :请求已成功,但响应体中的内容为空。
3xx:重定向状态码
- 301Moved Permanently(永久移出):资源已被永久移动到新的URL。
- 302Found(已找到):资源已被临时移动到新的URL。
- 304Not Modified(未修改):资源自上次请求以来未被修改,允许客户端使用缓存版本。
4xx:客户端错误状态码
- 400Bad Request(错误请求):请求无效或格式错误。
- 401Unauthorized(未授权):访问未授权;需要身份验证。
- 403Forbidden(禁止访问):服务器理解了请求,但拒绝被访问。
- 404Not Found(未找到):未找到请求的资源。
- 405Method Not Allowed(方法不被允许):对请求的资源不允许使用该HTTP方法。
5xx:服务器错误状态码
- 500Internal Server Error(内部服务器错误):服务器上发生了通用错误。
- 502Bad Gateway(错误网关):服务器在尝试履行请求时收到了无效响应。
- 503Service Unavailable(服务不可用):服务器暂时不可用,通常是由于过载或维护。
- 504Gateway Timeout(网关超时):服务器未及时从它尝试连接的另一台服务器上收到响应。
既然我们已经了解到所有状态类别以及最常用的状态码,那么我希望这个库能够支持所有可能的状态码。为此,我们将开发一个能够处理服务器返回的任何有效状态码的类。
创建CHttpStatusCode类
既然我们已经了解到所有可能的状态码,让我们将相应的实现添加到库中。这里的目标很简单:创建一个类,用于存储接收到的状态码。该类还应包含对每个状态码的描述支持,并且应该能够快速识别该状态码属于哪个类别。
让我们开始编写代码。在之前为CHttpMethod类创建的同一个文件夹中,我们将创建一个名为HttpStatusCode.mqh的新文件。最终,完整的路径将是Includes/Connexus/Constants/HttpStatusCode.mqh。
//+------------------------------------------------------------------+ //| HttpStatusCode.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+
为了包含所有可能的状态码,我们将创建一个枚举,其中包含所有可能的值。该枚举的名称将是 ENUM_HTTP_STATUS,枚举值是对应的状态码。
enum ENUM_HTTP_STATUS { //--- Mql error HTTP_STATUS_URL_NOT_ALLOWED = -1, HTTP_STATUS_URL_NOT_DEFINED = 1, HTTP_STATUS_METHOD_NOT_DEFINED = 2, //--- Informational HTTP_STATUS_CONTINUE = 100, HTTP_STATUS_SWITCHING_PROTOCOLS = 101, HTTP_STATUS_PROCESSING = 102, HTTP_STATUS_EARLY_HINTS = 103, //--- Successul HTTP_STATUS_OK = 200, HTTP_STATUS_CREATED = 201, HTTP_STATUS_ACCEPTED = 202, HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, HTTP_STATUS_NO_CONTENT = 204, HTTP_STATUS_RESET_CONTENT = 205, HTTP_STATUS_PARTIAL_CONTENT = 206, HTTP_STATUS_MULTI_STATUS = 207, HTTP_STATUS_ALREADY_REPORTED = 208, //--- Redirection messages HTTP_STATUS_MULTIPLE_CHOICES = 300, HTTP_STATUS_MOVED_PERMANENTLY = 301, HTTP_STATUS_FOUND = 302, HTTP_STATUS_SEE_OTHER = 303, HTTP_STATUS_NOT_MODIFIED = 304, HTTP_STATUS_USE_PROXY = 305, HTTP_STATUS_SWITCH_PROXY = 306, HTTP_STATUS_TEMPORARY_REDIRECT = 307, HTTP_STATUS_PERMANENT_REDIRECT = 308, //--- Client error HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_UNAUTHORIZED = 401, HTTP_STATUS_PAYMENT_REQUIRED = 402, HTTP_STATUS_FORBIDDEN = 403, HTTP_STATUS_NOT_FOUND = 404, HTTP_STATUS_METHOD_NOT_ALLOWED = 405, HTTP_STATUS_NOT_ACCEPTABLE = 406, HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, HTTP_STATUS_REQUEST_TIMEOUT = 408, HTTP_STATUS_CONFLICT = 409, HTTP_STATUS_GONE = 410, HTTP_STATUS_LENGTH_REQUIRED = 411, HTTP_STATUS_PRECONDITION_FAILED = 412, HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, HTTP_STATUS_URI_TOO_LONG = 414, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, HTTP_STATUS_EXPECTATION_FAILED = 417, HTTP_STATUS_MISDIRECTED_REQUEST = 421, HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, HTTP_STATUS_LOCKED = 423, HTTP_STATUS_FAILED_DEPENDENCY = 424, HTTP_STATUS_TOO_EARLY = 425, HTTP_STATUS_UPGRADE_REQUIRED = 426, HTTP_STATUS_PRECONDITION_REQUIRED = 428, HTTP_STATUS_TOO_MANY_REQUESTS = 429, HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, //--- Server error HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, HTTP_STATUS_NOT_IMPLEMENTED = 501, HTTP_STATUS_BAD_GATEWAY = 502, HTTP_STATUS_SERVICE_UNAVAILABLE = 503, HTTP_STATUS_GATEWAY_TIMEOUT = 504, HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, HTTP_STATUS_INSUFFICIENT_STORAGE = 507, HTTP_STATUS_LOOP_DETECTED = 508, HTTP_STATUS_NOT_EXTENDED = 510, HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511 };
请注意,我添加了一些注释来分隔不同类别的状态码。观察枚举的第一个值,我添加了这些值作为“自定义状态码”,它们将由库自动生成,这些自定义状态码包括:
- HTTP_STATUS_URL_NOT_ALLOWED:终端中未将该URL添加到允许的URL列表中
- HTTP_STATUS_URL_NOT_DEFINED:请求中未定义该URL
- HTTP_STATUS_METHOD_NOT_DEFINED:未给请求定义有效的方法
当调用WebRequest函数并返回-1时,根据MQL5文档的说明,意味着该URL未添加到终端中,因此库应自动返回HTTP_STATUS_URL_NOT_ALLOWED。类似的逻辑将应用于其他自定义状态码,但目前我们不会深入讨论这一点。
让我们继续开发这个类,其类似于CHttpMethod 类。我们将添加一个新的私有变量m_status,其类型为ENUM_HTTP_STATUS,并且还将添加一些辅助方法来设置和获取该变量的值:
- operator=(int) 和 operator=(ENUM_HTTP_STATUS):使用 = 运算符设置 m_status 的值,可以接收一个整数值或一个枚举值。
- Set(ENUM_HTTP_STATUS):使用枚举值设置状态码。
- Get() 和 GetMessage() :返回当前的状态码或仅返回与存储的状态码对应的消息。
以下是实现这些方法的代码:
//+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { private: ENUM_HTTP_STATUS m_status; // Stores the status used public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); //--- Set void operator=(int status); void operator=(ENUM_HTTP_STATUS status); void Set(ENUM_HTTP_STATUS status); //--- Get ENUM_HTTP_STATUS Get(void); string GetMessage(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Assignment operator to set status from integer value | //+------------------------------------------------------------------+ void CHttpStatusCodes::operator=(int status) { m_status = (ENUM_HTTP_STATUS)status; } //+------------------------------------------------------------------+ //| Assignment operator to set status from ENUM_HTTP_STATUS | //+------------------------------------------------------------------+ void CHttpStatusCodes::operator=(ENUM_HTTP_STATUS status) { m_status = status; } //+------------------------------------------------------------------+ //| Sets the HTTP status code | //+------------------------------------------------------------------+ void CHttpStatusCodes::Set(ENUM_HTTP_STATUS status) { m_status = status; } //+------------------------------------------------------------------+ //| Returns the stored HTTP status code | //+------------------------------------------------------------------+ ENUM_HTTP_STATUS CHttpStatusCodes::Get(void) { return(m_status); } //+------------------------------------------------------------------+ //| Returns a message corresponding to the stored HTTP status code | //+------------------------------------------------------------------+ string CHttpStatusCodes::GetMessage(void) { switch(m_status) { case HTTP_STATUS_URL_NOT_ALLOWED: return "The URL was not added to the list of allowed URLs in the terminal"; case HTTP_STATUS_URL_NOT_DEFINED: return "URL was not defined in the request"; case HTTP_STATUS_METHOD_NOT_DEFINED: return "Method was not defined in the request"; case HTTP_STATUS_CONTINUE: return "Continue"; case HTTP_STATUS_SWITCHING_PROTOCOLS: return "Switching Protocols"; case HTTP_STATUS_PROCESSING: return "Processing"; case HTTP_STATUS_EARLY_HINTS: return "Early Hints"; case HTTP_STATUS_OK: return "OK"; case HTTP_STATUS_CREATED: return "Created"; case HTTP_STATUS_ACCEPTED: return "Accepted"; case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION: return "Non-Authoritative Information"; case HTTP_STATUS_NO_CONTENT: return "No Content"; case HTTP_STATUS_RESET_CONTENT: return "Reset Content"; case HTTP_STATUS_PARTIAL_CONTENT: return "Partial Content"; case HTTP_STATUS_MULTI_STATUS: return "Multi-Status"; case HTTP_STATUS_ALREADY_REPORTED: return "Already Reported"; case HTTP_STATUS_MULTIPLE_CHOICES: return "Multiple Choices"; case HTTP_STATUS_MOVED_PERMANENTLY: return "Moved Permanently"; case HTTP_STATUS_FOUND: return "Found"; case HTTP_STATUS_SEE_OTHER: return "See Other"; case HTTP_STATUS_NOT_MODIFIED: return "Not Modified"; case HTTP_STATUS_USE_PROXY: return "Use Proxy"; case HTTP_STATUS_SWITCH_PROXY: return "Switch Proxy"; case HTTP_STATUS_TEMPORARY_REDIRECT: return "Temporary Redirect"; case HTTP_STATUS_PERMANENT_REDIRECT: return "Permanent Redirect"; case HTTP_STATUS_BAD_REQUEST: return "Bad Request"; case HTTP_STATUS_UNAUTHORIZED: return "Unauthorized"; case HTTP_STATUS_PAYMENT_REQUIRED: return "Payment Required"; case HTTP_STATUS_FORBIDDEN: return "Forbidden"; case HTTP_STATUS_NOT_FOUND: return "Not Found"; case HTTP_STATUS_METHOD_NOT_ALLOWED: return "Method Not Allowed"; case HTTP_STATUS_NOT_ACCEPTABLE: return "Not Acceptable"; case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED: return "Proxy Authentication Required"; case HTTP_STATUS_REQUEST_TIMEOUT: return "Request Timeout"; case HTTP_STATUS_CONFLICT: return "Conflict"; case HTTP_STATUS_GONE: return "Gone"; case HTTP_STATUS_LENGTH_REQUIRED: return "Length Required"; case HTTP_STATUS_PRECONDITION_FAILED: return "Precondition Failed"; case HTTP_STATUS_PAYLOAD_TOO_LARGE: return "Payload Too Large"; case HTTP_STATUS_URI_TOO_LONG: return "URI Too Long"; case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type"; case HTTP_STATUS_RANGE_NOT_SATISFIABLE: return "Range Not Satisfiable"; case HTTP_STATUS_EXPECTATION_FAILED: return "Expectation Failed"; case HTTP_STATUS_MISDIRECTED_REQUEST: return "Misdirected Request"; case HTTP_STATUS_UNPROCESSABLE_ENTITY: return "Unprocessable Entity"; case HTTP_STATUS_LOCKED: return "Locked"; case HTTP_STATUS_FAILED_DEPENDENCY: return "Failed Dependency"; case HTTP_STATUS_TOO_EARLY: return "Too Early"; case HTTP_STATUS_UPGRADE_REQUIRED: return "Upgrade Required"; case HTTP_STATUS_PRECONDITION_REQUIRED: return "Precondition Required"; case HTTP_STATUS_TOO_MANY_REQUESTS: return "Too Many Requests"; case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE: return "Request Header Fields Too Large"; case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS: return "Unavailable For Legal Reasons"; case HTTP_STATUS_INTERNAL_SERVER_ERROR: return "Internal Server Error"; case HTTP_STATUS_NOT_IMPLEMENTED: return "Not Implemented"; case HTTP_STATUS_BAD_GATEWAY: return "Bad Gateway"; case HTTP_STATUS_SERVICE_UNAVAILABLE: return "Service Unavailable"; case HTTP_STATUS_GATEWAY_TIMEOUT: return "Gateway Timeout"; case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED: return "HTTP Version Not Supported"; case HTTP_STATUS_VARIANT_ALSO_NEGOTIATES: return "Variant Also Negotiates"; case HTTP_STATUS_INSUFFICIENT_STORAGE: return "Insufficient Storage"; case HTTP_STATUS_LOOP_DETECTED: return "Loop Detected"; case HTTP_STATUS_NOT_EXTENDED: return "Not Extended"; case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED: return "Network Authentication Required"; default: return "Unknown HTTP Status"; } } //+------------------------------------------------------------------+
让我们再添加一些辅助方法,这些方法将负责检查类中存储的状态码是否属于特定的类别,方法包括:
- bool IsInformational(void):检查状态码是否属于信息性类别(范围 100 - 199)
- bool IsSuccess(void):检查状态码是否属于成功类别(范围 200 - 299)
- bool IsRedirection(void):检查状态码是否属于重定向类别(范围 300 - 399)
- bool IsClientError(void):检查状态码是否属于客户端错误类别(范围 400 - 499)
- bool IsServerError(void):检查状态码是否属于服务器错误类别(范围 500 - 599)
//+------------------------------------------------------------------+ //| class : CHttpStatusCodes | //| | //| [PROPERTY] | //| Name : CHttpStatusCodes | //| Heritage : No heritage | //| Description : Saved http status code. | //| | //+------------------------------------------------------------------+ class CHttpStatusCodes { private: ENUM_HTTP_STATUS m_status; // Stores the status used public: CHttpStatusCodes(void); ~CHttpStatusCodes(void); //--- Check which group the code is in bool IsInformational(void); // Checks if the status code is in the informational response range (100 - 199) bool IsSuccess(void); // Check if the status code is in the success range (200 - 299) bool IsRedirection(void); // Check if the status code is in the redirect range (300 - 399) bool IsClientError(void); // Checks if the status code is in the client error range (400 - 499) bool IsServerError(void); // Check if the status code is in the server error range (500 - 599) }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHttpStatusCodes::CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHttpStatusCodes::~CHttpStatusCodes(void) { } //+------------------------------------------------------------------+ //| Checks if the status code is in the informational response | //| range (100 - 199) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsInformational(void) { return(m_status >= 100 && m_status <= 199); } //+------------------------------------------------------------------+ //| Check if the status code is in the success range (200 - 299) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsSuccess(void) { return(m_status >= 200 && m_status <= 299); } //+------------------------------------------------------------------+ //| Check if the status code is in the redirect range (300 - 399) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsRedirection(void) { return(m_status >= 300 && m_status <= 399); } //+------------------------------------------------------------------+ //| Checks if the status code is in the client error range | //| (400 - 499) | //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsClientError(void) { return(m_status >= 400 && m_status <= 499); } //+------------------------------------------------------------------+ //| Check if the status code is in the server error range (500 - 599)| //+------------------------------------------------------------------+ bool CHttpStatusCodes::IsServerError(void) { return(m_status >= 500 && m_status <= 599); } //+------------------------------------------------------------------+
结论
为了让库的开发进度更加直观,请参考以下图表:
我们已经准备好了所有辅助类,这些类负责独立处理每个HTTP元素。我们拥有CQueryParam、CHttpHeader和CHttpBody类,它们都使用了CJson 类,但它们之间不存在继承关系。本文中创建的类尚未与其他类建立连接,在下一篇文章中,我们将通过创建一个HTTP请求和响应来将所有内容连接起来。
在本文中,我们了解到HTTP方法和状态码,这两者在客户端和服务器之间的网络通信中至关重要。了解每种方法的作用,可以让您更精确地发出请求,告知服务器您想要执行的操作,从而提高效率。每种方法在通信中都有其作用,正确使用这些方法可以使客户端和服务器之间的 API 通信更加清晰,避免出现意外情况。
此外,我们还讨论了状态码,这些状态码是服务器对请求处理结果的直接响应。从简单的“一切正常”(200 OK)到客户端错误(4xx)或服务器错误(5xx)消息不等。了解如何处理这些状态码是一项宝贵的技能,因为错误往往并不意味着结束,而是提供了调整或重试的机会。
在构建Connexus库的过程中,我们学习了如何处理这些元素,这使我们的库更加健壮,能够处理HTTP通信中的细微差别。从这里开始,我们负责处理方法和状态码的类将为开发人员在与 API 交互时提供更高水平的控制和安全性。
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/16136



