Шпаргалка по HTTP-библиотекам для С++

от автора

К сожалению, в стандартной библиотеке языка С++ нет никаких средств для работы с протоколом HTTP. Возможно, в будущем появятся, но на данный момент каждый раз при необходимости дёрнуть какой-нибудь REST-сервис, пропарсить веб-страничку, написать простенького бота или краулера приходится задаваться вопросами «А какую же библиотеку взять, так чтобы побыстрее и попроще?». Иногда проект уже использует какой-то фреймворк (а иногда даже несколько) и тогда приходится вспоминать «А как же сделать HTTP-запрос имеющимися средствами?». Чтобы не путаться я решил написать для себя шпаргалку с примерами HTTP-запросов на С++ с применением разных библиотек. А самое удобное место для хранения подобных шпаргалок — Хабр: и сам не потеряешь, и другим может пригодиться.

Будут рассмотрены:

  • WinInet
  • Casablanca
  • Qt
  • POCO
  • wxWidgets
  • Boost.Asio
  • libcurl
  • neon
  • .NET (С++/CLI)
  • IXMLHTTPRequest
  • HappyHttp
  • cpp-netlib

WinInet

Сайт: http://msdn.microsoft.com/en-us/library/windows/desktop/aa385483(v=vs.85).aspx
Платформа: Windows 95 и выше

Пример использования

 #include <tchar.h>     #include <wininet.h>        /// ....      HINTERNET hIntSession =        ::InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);      HINTERNET hHttpSession =        InternetConnect(hIntSession, _T("api.twitter.com"), 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);      HINTERNET hHttpRequest = HttpOpenRequest(       hHttpSession,        _T("GET"),        _T("1/statuses/user_timeline.xml?screen_name=twitterapi"),       0, 0, 0, INTERNET_FLAG_RELOAD, 0);      TCHAR* szHeaders = _T("Content-Type: text/html\nMySpecialHeder: whatever");     CHAR szReq[1024] = "";     if( !HttpSendRequest(hHttpRequest, szHeaders, _tcslen(szHeaders), szReq, strlen(szReq))) {       DWORD dwErr = GetLastError();       /// handle error     }      CHAR szBuffer[1025];     DWORD dwRead=0;     while(::InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer)-1, &dwRead) && dwRead) {       szBuffer[dwRead] = 0;       OutputDebugStringA(szBuffer);       dwRead=0;     }      ::InternetCloseHandle(hHttpRequest);     ::InternetCloseHandle(hHttpSession);     ::InternetCloseHandle(hIntSession); 

Casablanca

Сайт: https://casablanca.codeplex.com
Платформа: все

Пример использования

http_client client(L"http://www.myhttpserver.com"); http_request request(methods::GET); client.request(request).then([](http_response response)     {         // Perform actions here to inspect the HTTP response...         if(response.status_code() == status_codes::OK)         {         }     }); 

Qt

Сайт: http://qt-project.org
Платформа: все

Пример использования

#include "handler.h"   Handler::Handler(QObject *parent) :QObject(parent)  {     http = new QHttp(this);     connect(http, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)));     connect(http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), this, SLOT(responseHeaderReceived(QHttpResponseHeader)));     connect(http, SIGNAL(requestFinished(int,bool)), this, SLOT(requestFinished(int,bool))); }   void Handler::doHttp()  {     http->setHost("google.com");     http->get("/"); }   void Handler::stateChanged(int state)   {     switch(state)   {     case 0:         qDebug() << "Unconnected";         break;     case 1:         qDebug() << "Host Lookup";         break;     case 2:         qDebug() << "Connecting";         break;     case 3:         qDebug() << "Sending";         break;     case 4:         qDebug() << "Reading";         break;     case 5:         qDebug() << "Connect";         break;     case 6:         qDebug() << "Closing";         break;     } }   void Handler::responseHeaderReceived(const QHttpResponseHeader &resp)   {     qDebug() << "Size : " << resp.contentLength();     qDebug() << "Type : " << resp.contentType();     qDebug() << "Status Code : " << resp.statusCode(); }   void Handler::requestFinished(int id, bool error)   {     qDebug() << "Request Id : " << id;     if(error)   {         qDebug() << "Error";     }   else    {         qDebug() << http->readAll();     } } 

POCO

Сайт: http://pocoproject.org
Платформа: все

Пример использования

#include <Poco/Net/HTTPClientSession.h> #include <Poco/Net/HTTPRequest.h> #include <Poco/Net/HTTPResponse.h> #include <Poco/StreamCopier.h> #include <Poco/Path.h> #include <Poco/URI.h> #include <Poco/Exception.h> #include <iostream> #include <string>  using namespace Poco::Net; using namespace Poco; using namespace std;  int main(int argc, char **argv) {   if (argc != 2)   {     cout << "Usage: " << argv[0] << " <uri>" << endl;     cout << "       fetches the resource identified by <uri> and print it" << endl;     return -1;   }    try   {     // prepare session     URI uri(argv[1]);     HTTPClientSession session(uri.getHost(), uri.getPort());      // prepare path     string path(uri.getPathAndQuery());     if (path.empty()) path = "/";      // send request     HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);     session.sendRequest(req);      // get response     HTTPResponse res;     cout << res.getStatus() << " " << res.getReason() << endl;      // print response     istream &is = session.receiveResponse(res);     StreamCopier::copyStream(is, cout);   }   catch (Exception &ex)   {     cerr << ex.displayText() << endl;     return -1;   }    return 0; } 

wxWidgets

Сайт: http://www.wxwidgets.org
Платформа: все

Пример использования

#include <wx/sstream.h> #include <wx/protocol/http.h>   wxHTTP get; get.SetHeader(_T("Content-type"), _T("text/html; charset=utf-8")); get.SetTimeout(10); // 10 seconds of timeout instead of 10 minutes ...   // this will wait until the user connects to the internet. It is important in case of dialup (or ADSL) connections while (!get.Connect(_T("www.google.com")))  // only the server, no pages here yet ...     wxSleep(5);   wxApp::IsMainLoopRunning(); // should return true   // use _T("/") for index.html, index.php, default.asp, etc. wxInputStream *httpStream = get.GetInputStream(_T("/intl/en/about.html"));   // wxLogVerbose( wxString(_T(" GetInputStream: ")) << get.GetResponse() << _T("-") << ((resStream)? _T("OK ") : _T("FAILURE ")) << get.GetError() );   if (get.GetError() == wxPROTO_NOERR) {     wxString res;     wxStringOutputStream out_stream(&res);     httpStream->Read(out_stream);       wxMessageBox(res);     // wxLogVerbose( wxString(_T(" returned document length: ")) << res.Length() ); } else {     wxMessageBox(_T("Unable to connect!")); }   wxDELETE(httpStream); get.Close(); 

Boost.Asio

Сайт: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio.html
Платформа: все

Пример использования

#include <iostream> #include <istream> #include <ostream> #include <string> #include <boost/asio.hpp>  using boost::asio::ip::tcp;  int main(int argc, char* argv[]) {   try   {     if (argc != 3)     {       std::cout << "Usage: sync_client <server> <path>\n";       std::cout << "Example:\n";       std::cout << "  sync_client www.boost.org /LICENSE_1_0.txt\n";       return 1;     }      boost::asio::io_service io_service;      // Get a list of endpoints corresponding to the server name.     tcp::resolver resolver(io_service);     tcp::resolver::query query(argv[1], "http");     tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);      // Try each endpoint until we successfully establish a connection.     tcp::socket socket(io_service);     boost::asio::connect(socket, endpoint_iterator);      // Form the request. We specify the "Connection: close" header so that the     // server will close the socket after transmitting the response. This will     // allow us to treat all data up until the EOF as the content.     boost::asio::streambuf request;     std::ostream request_stream(&request);     request_stream << "GET " << argv[2] << " HTTP/1.0\r\n";     request_stream << "Host: " << argv[1] << "\r\n";     request_stream << "Accept: */*\r\n";     request_stream << "Connection: close\r\n\r\n";      // Send the request.     boost::asio::write(socket, request);      // Read the response status line. The response streambuf will automatically     // grow to accommodate the entire line. The growth may be limited by passing     // a maximum size to the streambuf constructor.     boost::asio::streambuf response;     boost::asio::read_until(socket, response, "\r\n");      // Check that response is OK.     std::istream response_stream(&response);     std::string http_version;     response_stream >> http_version;     unsigned int status_code;     response_stream >> status_code;     std::string status_message;     std::getline(response_stream, status_message);     if (!response_stream || http_version.substr(0, 5) != "HTTP/")     {       std::cout << "Invalid response\n";       return 1;     }     if (status_code != 200)     {       std::cout << "Response returned with status code " << status_code << "\n";       return 1;     }      // Read the response headers, which are terminated by a blank line.     boost::asio::read_until(socket, response, "\r\n\r\n");      // Process the response headers.     std::string header;     while (std::getline(response_stream, header) && header != "\r")       std::cout << header << "\n";     std::cout << "\n";      // Write whatever content we already have to output.     if (response.size() > 0)       std::cout << &response;      // Read until EOF, writing data to output as we go.     boost::system::error_code error;     while (boost::asio::read(socket, response,           boost::asio::transfer_at_least(1), error))       std::cout << &response;     if (error != boost::asio::error::eof)       throw boost::system::system_error(error);   }   catch (std::exception& e)   {     std::cout << "Exception: " << e.what() << "\n";   }    return 0; } 

libcurl

Сайт: http://curl.haxx.se/libcurl
Платформа: все

Пример использования

#include <stdio.h> #include <curl/curl.h>   int main(void) {   CURL *curl;   CURLcode res;     curl = curl_easy_init();   if(curl) {     curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");     /* example.com is redirected, so we tell libcurl to follow redirection */      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);       /* Perform the request, res will get the return code */      res = curl_easy_perform(curl);     /* Check for errors */      if(res != CURLE_OK)       fprintf(stderr, "curl_easy_perform() failed: %s\n",               curl_easy_strerror(res));       /* always cleanup */      curl_easy_cleanup(curl);   }   return 0; } 

neon

Сайт: http://www.webdav.org/neon
Платформа: все

Пример использования

#include <ne_session.h> #include <ne_request.h> #include <ne_utils.h> #include <ne_uri.h>  int httpResponseReader(void *userdata, const char *buf, size_t len) {     string *str = (string *)userdata;     str->append(buf, len);     return 0; }   int do_get(string host) {     ne_session *sess;     ne_request *req;     string response;       ne_sock_init();       sess = ne_session_create("http", host.c_str(), 80);     ne_set_useragent(sess, "MyAgent/1.0");       req = ne_request_create(sess, "GET", "/SomeURL/method?with=parameter&value=data");     // if accepting only 2xx codes, use "ne_accept_2xx"     ne_add_response_body_reader(req, ne_accept_always, httpResponseReader, &response);       int result = ne_request_dispatch(req);     int status = ne_get_status(req)->code;       ne_request_destroy(req);       string errorMessage = ne_get_error(sess);     ne_session_destroy(sess);       printf("result %d, status %d\n", result, status);     cout << response << "\n";       switch (result) {     case NE_OK:         break;     case NE_CONNECT:         throw ConnectionError(errorMessage);     case NE_TIMEOUT:         throw TimeOutError(errorMessage);     case NE_AUTH:         throw AuthenticationError(errorMessage);     default:         throw AnotherWebError(errorMessage);     }       return 0; } 

.NET

Сайт: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.aspx
Платформа: Windows XP и выше

Пример использования

#using <System.dll>  using namespace System; using namespace System::Net; using namespace System::Text; using namespace System::IO;  // Specify the URL to receive the request. int main() {    array<String^>^args = Environment::GetCommandLineArgs();    HttpWebRequest^ request = dynamic_cast<HttpWebRequest^>(WebRequest::Create( args[ 1 ] ));     // Set some reasonable limits on resources used by this request    request->MaximumAutomaticRedirections = 4;    request->MaximumResponseHeadersLength = 4;     // Set credentials to use for this request.    request->Credentials = CredentialCache::DefaultCredentials;    HttpWebResponse^ response = dynamic_cast<HttpWebResponse^>(request->GetResponse());    Console::WriteLine( "Content length is {0}", response->ContentLength );    Console::WriteLine( "Content type is {0}", response->ContentType );     // Get the stream associated with the response.    Stream^ receiveStream = response->GetResponseStream();     // Pipes the stream to a higher level stream reader with the required encoding format.     StreamReader^ readStream = gcnew StreamReader( receiveStream,Encoding::UTF8 );    Console::WriteLine( "Response stream received." );    Console::WriteLine( readStream->ReadToEnd() );    response->Close();    readStream->Close(); } 

IXMLHTTPRequest

Сайт: http://msdn.microsoft.com/en-us/library/ms759148(v=vs.85).aspx
Платформа: Windows XP и выше

Пример использования

#include <atlbase.h> #include <msxml6.h>  HRESULT hr; CComPtr<IXMLHTTPRequest> request;  hr = request.CoCreateInstance(CLSID_XMLHTTP60); hr = request->open(     _bstr_t("GET"),     _bstr_t("https://www.google.com/images/srpr/logo11w.png"),     _variant_t(VARIANT_FALSE),     _variant_t(),     _variant_t()); hr = request->send(_variant_t());  // get status - 200 if succuss long status; hr = request->get_status(&status);  // load image data (if url points to an image) VARIANT responseVariant; hr = request->get_responseStream(&responseVariant); IStream* stream = (IStream*)responseVariant.punkVal; CImage *image = new CImage(); image->Load(stream); stream->Release(); 

HappyHttp

Сайт: http://scumways.com/happyhttp/happyhttp.html
Платформа: все

Пример использования

static int count=0;  // invoked when response headers have been received void OnBegin( const happyhttp::Response* r, void* userdata ) { 	printf( "BEGIN (%d %s)\n", r->getstatus(), r->getreason() ); 	count = 0; }  // invoked to process response body data (may be called multiple times) void OnData( const happyhttp::Response* r, void* userdata, const unsigned char* data, int n ) { 	fwrite( data,1,n, stdout ); 	count += n; }  // invoked when response is complete void OnComplete( const happyhttp::Response* r, void* userdata ) { 	printf( "COMPLETE (%d bytes)\n", count ); }   void TestGET() { 	happyhttp::Connection conn( "www.scumways.com", 80 ); 	conn.setcallbacks( OnBegin, OnData, OnComplete, 0 );  	conn.request( "GET", "/happyhttp/test.php" );  	while( conn.outstanding() ) 		conn.pump(); } 

cpp-netlib

Сайт: http://cpp-netlib.org
Платформа: все

Пример использования

using namespace boost::network; using namespace boost::network::http;  client::request request_("http://127.0.0.1:8000/"); request_ << header("Connection", "close"); client client_; client::response response_ = client_.get(request_); std::string body_ = body(response_); 

Так, скажи уже в конце концов, что использовать!

Хотите проверенной годами классики — берите libcurl. Пишете приложение с визуальным интерфейсом — берите Qt. Хотите современного С++11 — берите Casablanca. Пишете под .NET — используйте стандартные средства платформы. Пишете что-то без интерфейса и кроме HTTP-клиента хотите вообще иметь разные удобные инструменты — Boost или POCO.

ссылка на оригинал статьи http://habrahabr.ru/company/infopulse/blog/226557/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *