How to send a POST with a JSON in a WebRequest() call using MQL4?

前端 未结 4 1291
旧时难觅i
旧时难觅i 2020-12-16 23:52

I would like to send a POST from MQL4-script, using a JSON-format to a Node-server.

I\'ve tried the webReque

相关标签:
4条回答
  • 2020-12-17 00:27

    So, back to the square No.1:

    In the last-year's post, there was a step by step methodology to proceed with a MCVE-based approach to the problem isolation.

    Repeating the same steps here, inside MQL4-code,
    adding a python-based mock-up WebSERVER, to diagnose the actual working client/server http-protocol exchange & handshaking, ( not the WebSERVER-side interpretation of the delivered POST-request, which is the same, as if one have launched the URL from a WebBROWSER, for all related details ref: BaseHTTPServer.BaseHTTPRequestHandler )

    >>> import BaseHTTPServer
    >>> server_class  = BaseHTTPServer.HTTPServer
    >>> handler_class = BaseHTTPServer.BaseHTTPRequestHandler
    >>> httpd         = server_class( ( '', 8765 ), handler_class )
    >>> httpd.handle_request()
    127.0.0.1 - - [10/Oct/2016 09:46:45] code 501, message Unsupported method ('GET')
    127.0.0.1 - - [10/Oct/2016 09:46:45] "GET /?test=123_from_Chrome HTTP/1.1" 501 -
    >>> httpd.handle_request()
    127.0.0.1 - - [10/Oct/2016 09:47:23] code 501, message Unsupported method ('GET')
    127.0.0.1 - - [10/Oct/2016 09:47:23] "GET /favicon.ico HTTP/1.1" 501 -
    >>>
    >>>
    >>>
    >>> httpd = server_class( ( '', 80 ), handler_class )
    >>> httpd.handle_request()
    127.0.0.1 - - [10/Oct/2016 10:22:05] code 501, message Unsupported method ('GET')
    127.0.0.1 - - [10/Oct/2016 10:22:05] "GET /?test=123_from_Chrome_on_port_80 HTTP/1.1" 501 -
    >>> httpd.handle_request()
    127.0.0.1 - - [10/Oct/2016 10:22:31] code 501, message Unsupported method ('GET')
    127.0.0.1 - - [10/Oct/2016 10:22:31] "GET /?test=123_from_Chrome_on_port_80_again HTTP/1.1" 501 -
    >>> httpd.handle_request()
    127.0.0.1 - - [10/Oct/2016 10:22:34] code 501, message Unsupported method ('GET')
    127.0.0.1 - - [10/Oct/2016 10:22:34] "GET /favicon.ico HTTP/1.1" 501 -
    >>> httpd.handle_request()
    127.0.0.1 - - [10/Oct/2016 11:25:56] code 501, message Unsupported method ('GET')
    127.0.0.1 - - [10/Oct/2016 11:26:12] "GET /?test=123_from_Chrome_on_port_80_another_call HTTP/1.1" 501 -
    >>>
    >>>
    127.0.0.1 - - [10/Oct/2016 12:03:03] code 501, message Unsupported method ('POST')
    127.0.0.1 - - [10/Oct/2016 12:03:03] "POST / HTTP/1.1" 501 -
    >>>
    

    the output is
    providing an evidence that the last pair of rows were produced by an MQL4-side WebRequest() that was setup correctly and works fine there and back
    [ MetaTrader Terminal 4 ]-Log reads:

    2016.10.10 12:03:03.921 ___StackOverflow_WebRequest_DEMO XAUUSD,H1:
    
               DATA:: <head><title>Error response</title></head>
                      <body>
                      <h1>Error response</h1><p>Error code 501.<p>
                      Message: Unsupported method ('POST').<p>
                      Error code explanation: 501 = Server does not support this operation.
                      </body>
    
    2016.10.10 12:03:03.921 ___StackOverflow_WebRequest_DEMO XAUUSD,H1:
    
               HDRs:: HTTP/1.0 501 Unsupported method ('POST')
                      Server: BaseHTTP/0.3 Python/2.7.6
                      Date: Mon, 10 Oct 2016 20:03:03 GMT
                      Content-Type: text/html
                      Connection: close
    

    A raw MQL4-snippet BUT use at one's own risk!

    ( strongly encourage NOT to use any BLOCKING WebRequest() calls
    in any Production-grade code...for NON-BLOCKING tools see my other posts and how to or read into internal details on high-performance, low-latency, non-blocking integration tools for distributed heterogeneous systems processing alike ZeroMQ or nanomsg )

    All have been warned, so:

    Last years setup picture is still valid:

    The mock-up WebSERVER had inside the dotted form-field input of:

    http://localhost/
    

    One shall also bear in mind, that trying to set a specific port designation in the URL will violate the MetaQuotes Inc. design rule, that a port is being derived from the protocol pragma at the beginning of the URL declaration, so:

    http://localhost:8765/
    

    will not work, as MQL4 WebRequest() CANNOT use other port but either of { 80 | 443 }, given by protocol pragma stated in URL: { http: | https: }

    Thus for any port-numbering gymnastics, one has to setup and tune a proper set of port-forwarding services, that would leave MetaTrader Terminal 4 live inside this design-cage, using just either of { 80 | 443 }.

    The simplest MQL4-script OnStart() demonstrator looks this way:

    //+------------------------------------------------------------------+
    //|                             ___StackOverflow_WebRequest_DEMO.mq4 |
    //|                                       Copyright © 1987-2016 [MS] |
    //|                                                       nowhere.no |
    //+------------------------------------------------------------------+ >>> https://stackoverflow.com/questions/39954177/how-to-send-a-post-with-a-json-in-a-webrequest-call-using-mql4
    #property copyright "Copyright © 1987-2016 [MS]"
    #property link      "nowhere.no"
    #property version   "1.00"
    #property strict
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void  OnStart(){
    
          /* A BRIGHTER WAY:
    
             string JSON_string = StringFormat( "{\"currency\": \"%s\", \"timeframe\": \"%d\", \"ticktime\": \"%s\", \"bid\": %f, \"ask\": %f, \"spread\": %s }",  _Symbol,
                                                                                                                                                                   Period(),
                                                                                                                                                                   TimeToString( TimeLocal(), TIME_DATE | TIME_SECONDS ),
                                                                                                                                                                   MarketInfo( _Symbol, MODE_BID ),
                                                                                                                                                                   MarketInfo( _Symbol, MODE_ASK ),
                                                                                                                                                                   MarketInfo( _Symbol, MODE_SPREAD )
                                                                                                                                                                   );
          // A SMARTER WAY & THE FASTEST PROCESSING TIMES:
          // --------------
    
    #define MQL4_COMPILE_TIME_JSON_TEMPLATE     "{\"currency\": \"%s\", \"timeframe\": \"%d\", \"ticktime\": \"%s\", \"bid\": %f, \"ask\": %f, \"spread\": %s }"   // CONSTANT TEMPLATE TO FILL-IN AD-HOC VALUES:
          // +
             string JSON_string = StringFormat( MQL4_COMPILE_TIME_JSON_TEMPLATE",                                                                                  _Symbol,
                                                                                                                                                                   Period(),
                                                                                                                                                                   TimeToString( TimeLocal(), TIME_DATE | TIME_SECONDS ),
                                                                                                                                                                   MarketInfo( _Symbol, MODE_BID ),
                                                                                                                                                                   MarketInfo( _Symbol, MODE_ASK ),
                                                                                                                                                                   MarketInfo( _Symbol, MODE_SPREAD )
                                                                                                                                                                   );
             */
          string JSON_string = StringConcatenate( "{",                                                    // **** MQL4 can concat max 63 items
                                                  "\"currency\"",
                                                  ":",
                                                  "\"",
                                                  Symbol(),
                                                  "\"",
                                                  ",",
                                                  "\"timeframe\"",
                                                  ":",
                                                  "\"",
                                                  IntegerToString( Period() ),
                                                  "\"",
                                                  ",",
                                                  "\"ticktime\"",
                                                  ":",
                                                  "\"",
                                                  TimeToString( TimeLocal(), TIME_DATE | TIME_SECONDS ),
                                                  "\"",
                                                  ",",
                                                  "\"bid\"",
                                                  ":",
                                                  DoubleToString( MarketInfo( Symbol(), MODE_BID ), 4 ),
                                                  ",",
                                                  "\"ask\"",
                                                  ":",
                                                  DoubleToString( MarketInfo( Symbol(), MODE_ASK ), 4 ),
                                                  ",",
                                                  "\"spread\"",
                                                  ":",
                                                  DoubleToString( MarketInfo( Symbol(), MODE_SPREAD ), 0 ),
                                                  "}"
                                                  );
       // */
       /* off-topic: a JSON-string VALIDATOR -----------------------------------------------------------------------------------------------------------------------------------
    
    #include <Json\hash.mqh>
    #include <Json\KoulJSONMgmt.mqh>
    
            JSONParser *parser = new JSONParser();
            JSONValue  *jv     =         parser.parse(strParam);
    
            string strJson = jv.toString();
    
            if ( jv == NULL ) Print( "ERROR:"  + (string) parser.getErrorCode()
                                                        + parser.getErrorMessage()
                                     );
            else              Print( "PARSED:" + strJson );
    
                              // Example of a journalled Print() for an above setup JSON String :
                              // EURUSD,M15: PARSED:{"bid" : 1.1152,"ask" : 1.1154,"spread" : 13,"ticktime" : "2016.10.10 16:24:01","currency" : "EURUSD","timeframe" : "15"}
    */ // off-topic: a JSON-string VALIDATOR -----------------------------------------------------------------------------------------------------------------------------------
    
           // string  ReqSERVER_URL = "http://localhost:8765/",         // **** MQL4 WebRequest CANNOT use other port but either of { 80 | 443 } given by protocol pragma stated in URL: { http: | https: }
              string  ReqSERVER_URL = "http://localhost/",              // ---- MQL4 WebRequst
                      ReqCOOKIE     =  NULL,
                   // ReqHEADERs    =               "application/json"; // **** MQL4 WebRequest MUST   use [in]  Request headers of type "key: value", separated by a line break "\r\n".
                      ReqHEADERs    = "Content-Type: application/json\r\n";
              int     ReqTIMEOUT    =  5000;                            // ---- MQL4 WebRequest SHALL  use [in]  Timeouts below 1000 (1 sec.) are not enough for slow Internet connection;
                   // ================================================= // ~~~~ MQL4 WebRequest SHALL be AVOIDED as an un-control-able BLOCKING-SHOW-STOPPER, any professional need shall use NON-BLOCKING tools
              char    POSTed_DATA[],
                      result_RECVed_DATA_FromSERVER[];
              int     result_RetCODE;
              string  result_DecodedFromSERVER,
                      result_RECVed_HDRs_FromSERVER;
    
           // int     intHostNameLength                       = StringLen(  ReqSERVER_URL );
           // StringToCharArray( ReqSERVER_URL, POSTed_DATA, 0, StringLen(  ReqSERVER_URL ) );
           // StringToCharArray( prmParameter,  post,        0, intHostNameLength );
              StringToCharArray( JSON_string,   POSTed_DATA, 0, StringLen(  JSON_string   ) );
    
              ResetLastError();
    
              result_RetCODE = WebRequest( "POST",
                                           ReqSERVER_URL,
                                           ReqHEADERs,
                                           ReqTIMEOUT,
                                           POSTed_DATA,
                                           result_RECVed_DATA_FromSERVER,
                                           result_RECVed_HDRs_FromSERVER
                                           );
              if (  result_RetCODE == -1 ) Print( "Error in WebRequest. Error code  =", GetLastError() ); // returns error 4060 – "Function is not allowed for call" unless permitted -- ref. Picture in >>> https://stackoverflow.com/questions/39954177/how-to-send-a-post-with-a-json-in-a-webrequest-call-using-mql4
              else {
                    for (  int i = 0; i < ArraySize( result_RECVed_DATA_FromSERVER ); i++ ) {
                           if (  ( result_RECVed_DATA_FromSERVER[i] == 10 ) // == '\n'  // <LF>
                              || ( result_RECVed_DATA_FromSERVER[i] == 13 ) // == '\r'  // <CR>
                              ) 
                              continue;
                           else     result_DecodedFromSERVER += CharToStr( result_RECVed_DATA_FromSERVER[i] );
                    }
                    Print( "DATA:: ", result_DecodedFromSERVER );
                    Print( "HDRs:: ", result_RECVed_HDRs_FromSERVER );
              }
          }
    //+------------------------------------------------------------------+
    

    Deviations from documented steps are easily visible in the source and were left for clarity.


    Epilogue:

    If documentation says something, it is worth keeping that advice ( with some tests, sure ).

    If a sponsored Community advice says something, it is worth giving it at least a try, before asking for more.

    0 讨论(0)
  • 2020-12-17 00:30

    Have you tried setting the headers like this:

    headers = "Content-Type: application/json\r\n";
    

    ?

    0 讨论(0)
  • 2020-12-17 00:31

    It works well for me, I have someone like this :

    string response = SendResquest("POST", "GetPrediction", "[4, 7]", "Content-Type: application/json", 5000);
    
    string SendResquest(string httpType, string methodName, string bodyData = "", string headers = "", int timeout)
    {
        uchar bodyDataCharArray[];
        ArrayResize(bodyDataCharArray, StringToCharArray(bodyData, bodyDataCharArray)-1);
    
        int response = WebRequest(httpType, this.address+methodName, headers, timeout, bodyDataCharArray, this.resultDataCharArray, this.resultHeader);
    
        string result = CharArrayToString(this.resultDataCharArray); 
    
        if(response == 200)
            return result;
        Print("Error when trying to call API : ", response);
        return "";
    }
    
    0 讨论(0)
  • Allow your [ MetaTrader Terminal 4 ] to communicate with URL via menu:

    Tools -> Options -> Expert Advisors ->

    1. mark a check-box [ X ] in front of 'Allow WebReq....'
    &
    2. type the URL name below the check-box, using the green (+) icon, inside the form.

    If this doesn't help - try to add Print() statements to see the possible errors ( incorrect MQL4 code or incorrect JSON-format file ).

    0 讨论(0)
提交回复
热议问题