#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/strand.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
void
fail(beast::error_code ec, char const* what)
{
std::cerr << what << ": " << ec.message() << "\n";
}
// Performs an HTTP GET and prints the response
class httpClient : public std::enable_shared_from_this<httpClient>
{
tcp::resolver resolver_;
beast::tcp_stream stream_;
beast::flat_buffer buffer_; // (Must persist between reads)
http::request<http::empty_body> req_;
http::response<http::string_body> res_;
public:
// Objects are constructed with a strand to
// ensure that handlers do not execute concurrently.
explicit
httpClient(net::io_context& ioc)
: resolver_(net::make_strand(ioc))
, stream_(net::make_strand(ioc))
{
}
// Start the asynchronous operation
void
run(
char const* host,
char const* port,
char const* target)
{
req_.method(http::verb::get);
req_.target(target);
req_.set(http::field::host, host);
req_.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Look up the domain name
resolver_.async_resolve(
host,
port,
beast::bind_front_handler(
&httpClient::on_resolve,
shared_from_this()));
}
void
on_resolve(
beast::error_code ec,
tcp::resolver::results_type results)
{
if(ec)
return fail(ec, "resolve");
// Set a timeout on the operation
stream_.expires_after(std::chrono::seconds(30));
// Make the connection on the IP address we get from a lookup
stream_.async_connect(
results,
beast::bind_front_handler(
&httpClient::on_connect,
shared_from_this()));
}
void
on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type)
{
if(ec)
return fail(ec, "connect");
// Set a timeout on the operation
stream_.expires_after(std::chrono::seconds(30));
// Send the HTTP request to the remote host
http::async_write(stream_, req_,
beast::bind_front_handler(
&httpClient::on_write,
shared_from_this()));
}
void
on_write(
beast::error_code ec,
std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if(ec)
return fail(ec, "write");
// Receive the HTTP response
http::async_read(stream_, buffer_, res_,
beast::bind_front_handler(
&httpClient::on_read,
shared_from_this()));
}
void
on_read(
beast::error_code ec,
std::size_t bytes_transferred)
{
boost::ignore_unused(bytes_transferred);
if(ec)
return fail(ec, "read");
// Write the message to standard out
std::cout << res_ << std::endl;
// Gracefully close the socket
stream_.socket().shutdown(tcp::socket::shutdown_both, ec);
// not_connected happens sometimes so don't bother reporting it.
if(ec && ec != beast::errc::not_connected)
return fail(ec, "shutdown");
// If we get here then the connection is closed gracefully
}
};
//------------------------------------------------------------------------------
int main(int argc, char** argv)
{
// The io_context is required for all I/O
net::io_context ioc;
// Launch the asynchronous operation
std::make_shared<httpClient>(ioc)->run("api.binance.com", "443", "/api/v3/depth");
// Run the I/O service. The call will return when
// the get operation is complete.
ioc.run();
return EXIT_SUCCESS;
}
docs : https://binance-docs.github.io/apidocs/spot/en/#order-book
I am trying to get the order-book snapshot using http request, it seems that it is not working.
whats wrong here ?
Also, some other endpoints require api key configuration and i haven't found a single beast http client example that lets you do it.
advance thanks!
error :
HTTP/1.1 400 Bad Request
Server: CloudFront
Date: Thu, 21 Apr 2022 10:53:24 GMT
Content-Type: text/html
Content-Length: 915
Connection: close
X-Cache: Error from cloudfront
Via: 1.1 a341af1380e4410f261315636c58a456.cloudfront.net (CloudFront)
X-Amz-Cf-Pop: MAA51-P1
X-Amz-Cf-Id: _JRJDU8BRaTjSLea6xtyByU_IGX0zHfCbM96W10KSh57fAsMV5AvOw==
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>400 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
Bad request.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: _JRJDU8BRaTjSLea6xtyByU_IGX0zHfCbM96W10KSh57fAsMV5AvOw==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>
CodePudding user response:
You are doing a plain HTTP request to a HTTPS service. There is nothing wrong per se with your code, and you can reproduce exactly the same answer using e.g. curl:
$ curl http://api.binance.com:443/api/v3/depth
You may take a look at some of the beast examples using SSL. As far as I remember, beast lets you exchange the underlying stream from a plain TCP socket to a SSL socket.
Edit
For the api key configuration, you must elaborate more exactly what is needed.
Also remember, that boost beast is a very generic and low level library. There are only the most basic examples in the documentation, because the library is meant for library developers primarly. While beast is imho a brilliant library, there might be other web client libraries, that are easier to use if you only need to make simple web requests.