Как вы делаете HTTP-запрос с C++?
Есть ли способ легко сделать HTTP-запрос с C++? В частности, я хочу загрузить содержимое страницы (API) и проверить содержимое, чтобы увидеть, содержит ли оно 1 или 0. Можно ли также загрузить содержимое в строку?
25 ответов
У меня такая же проблема. libcurl действительно завершен. Существует обертка C++ curlpp, которая может вас заинтересовать, когда вы запрашиваете библиотеку C++. Neon - еще одна интересная библиотека C, которая также поддерживает WebDAV.
curlpp кажется естественным, если вы используете C++. В исходном дистрибутиве приведено много примеров. Чтобы получить содержание URL, вы делаете что-то подобное (извлечено из примеров):
// Edit : rewritten for cURLpp 0.7.3
// Note : namespace changed, was cURLpp in 0.7.2 ...
#include <curlpp/cURLpp.hpp>
#include <curlpp/Options.hpp>
// RAII cleanup
curlpp::Cleanup myCleanup;
// Send request and get a result.
// Here I use a shortcut to get it in a string stream ...
std::ostringstream os;
os << curlpp::options::Url(std::string("http://www.wikipedia.org"));
string asAskedInQuestion = os.str();
Увидеть examples
каталог в дистрибутиве исходного кода curlpp, есть много более сложных случаев, а также простой полный минимальный с использованием curlpp.
мои 2 цента...
Код Windows:
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <locale>
#include <sstream>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int main( void ){
WSADATA wsaData;
SOCKET Socket;
SOCKADDR_IN SockAddr;
int lineCount=0;
int rowCount=0;
struct hostent *host;
locale local;
char buffer[10000];
int i = 0 ;
int nDataLength;
string website_HTML;
// website url
string url = "www.google.com";
//HTTP GET
string get_http = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n";
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
cout << "WSAStartup failed.\n";
system("pause");
//return 1;
}
Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
host = gethostbyname(url.c_str());
SockAddr.sin_port=htons(80);
SockAddr.sin_family=AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
cout << "Could not connect";
system("pause");
//return 1;
}
// send GET / HTTP
send(Socket,get_http.c_str(), strlen(get_http.c_str()),0 );
// recieve html
while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){
website_HTML+=buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
// Display HTML source
cout<<website_HTML;
// pause
cout<<"\n\nPress ANY key to close.\n\n";
cin.ignore(); cin.get();
return 0;
}
Вот намного лучшая реализация:
#include <windows.h>
#include <string>
#include <stdio.h>
using std::string;
#pragma comment(lib,"ws2_32.lib")
HINSTANCE hInst;
WSADATA wsaData;
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename);
SOCKET connectToServer(char *szServerName, WORD portNum);
int getHeaderLength(char *content);
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut);
int main()
{
const int bufLen = 1024;
char *szUrl = "http://stackru.com";
long fileSize;
char *memBuffer, *headerBuffer;
FILE *fp;
memBuffer = headerBuffer = NULL;
if ( WSAStartup(0x101, &wsaData) != 0)
return -1;
memBuffer = readUrl2(szUrl, fileSize, &headerBuffer);
printf("returned from readUrl\n");
printf("data returned:\n%s", memBuffer);
if (fileSize != 0)
{
printf("Got some data\n");
fp = fopen("downloaded.file", "wb");
fwrite(memBuffer, 1, fileSize, fp);
fclose(fp);
delete(memBuffer);
delete(headerBuffer);
}
WSACleanup();
return 0;
}
void mParseUrl(char *mUrl, string &serverName, string &filepath, string &filename)
{
string::size_type n;
string url = mUrl;
if (url.substr(0,7) == "http://")
url.erase(0,7);
if (url.substr(0,8) == "https://")
url.erase(0,8);
n = url.find('/');
if (n != string::npos)
{
serverName = url.substr(0,n);
filepath = url.substr(n);
n = filepath.rfind('/');
filename = filepath.substr(n+1);
}
else
{
serverName = url;
filepath = "/";
filename = "";
}
}
SOCKET connectToServer(char *szServerName, WORD portNum)
{
struct hostent *hp;
unsigned int addr;
struct sockaddr_in server;
SOCKET conn;
conn = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (conn == INVALID_SOCKET)
return NULL;
if(inet_addr(szServerName)==INADDR_NONE)
{
hp=gethostbyname(szServerName);
}
else
{
addr=inet_addr(szServerName);
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
closesocket(conn);
return NULL;
}
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
server.sin_family=AF_INET;
server.sin_port=htons(portNum);
if(connect(conn,(struct sockaddr*)&server,sizeof(server)))
{
closesocket(conn);
return NULL;
}
return conn;
}
int getHeaderLength(char *content)
{
const char *srchStr1 = "\r\n\r\n", *srchStr2 = "\n\r\n\r";
char *findPos;
int ofset = -1;
findPos = strstr(content, srchStr1);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr1);
}
else
{
findPos = strstr(content, srchStr2);
if (findPos != NULL)
{
ofset = findPos - content;
ofset += strlen(srchStr2);
}
}
return ofset;
}
char *readUrl2(char *szUrl, long &bytesReturnedOut, char **headerOut)
{
const int bufSize = 512;
char readBuffer[bufSize], sendBuffer[bufSize], tmpBuffer[bufSize];
char *tmpResult=NULL, *result;
SOCKET conn;
string server, filepath, filename;
long totalBytesRead, thisReadSize, headerLen;
mParseUrl(szUrl, server, filepath, filename);
///////////// step 1, connect //////////////////////
conn = connectToServer((char*)server.c_str(), 80);
///////////// step 2, send GET request /////////////
sprintf(tmpBuffer, "GET %s HTTP/1.0", filepath.c_str());
strcpy(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
sprintf(tmpBuffer, "Host: %s", server.c_str());
strcat(sendBuffer, tmpBuffer);
strcat(sendBuffer, "\r\n");
strcat(sendBuffer, "\r\n");
send(conn, sendBuffer, strlen(sendBuffer), 0);
// SetWindowText(edit3Hwnd, sendBuffer);
printf("Buffer being sent:\n%s", sendBuffer);
///////////// step 3 - get received bytes ////////////////
// Receive until the peer closes the connection
totalBytesRead = 0;
while(1)
{
memset(readBuffer, 0, bufSize);
thisReadSize = recv (conn, readBuffer, bufSize, 0);
if ( thisReadSize <= 0 )
break;
tmpResult = (char*)realloc(tmpResult, thisReadSize+totalBytesRead);
memcpy(tmpResult+totalBytesRead, readBuffer, thisReadSize);
totalBytesRead += thisReadSize;
}
headerLen = getHeaderLength(tmpResult);
long contenLen = totalBytesRead-headerLen;
result = new char[contenLen+1];
memcpy(result, tmpResult+headerLen, contenLen);
result[contenLen] = 0x0;
char *myTmp;
myTmp = new char[headerLen+1];
strncpy(myTmp, tmpResult, headerLen);
myTmp[headerLen] = NULL;
delete(tmpResult);
*headerOut = myTmp;
bytesReturnedOut = contenLen;
closesocket(conn);
return(result);
}
В Linux я попробовал cpp-netlib, libcurl, curlpp, urdl, boost::asio и рассмотрел Qt (но отклонил его на основании лицензии). Все они были неполными для этого использования, имели небрежные интерфейсы, имели плохую документацию, не обслуживались или не поддерживали https.
Затем по предложению https://stackru.com/a/1012577/278976 я попробовал POCO. Ух ты, жаль, что я не видел это много лет назад. Вот пример выполнения HTTP-запроса GET:
http://xjia.heroku.com/2011/09/10/learning-poco-get-with-http/
POCO является бесплатным, с открытым исходным кодом (лицензия Boost). И нет, я не имею никакого отношения к компании; Мне просто очень нравятся их интерфейсы. Отличная работа, ребята (и девочки).
http://pocoproject.org/download/index.html
Надеюсь, это кому-нибудь поможет... Мне понадобилось три дня, чтобы опробовать все эти библиотеки.
Существует новая, менее зрелая оболочка для завитков, которая называется C++ Requests. Вот простой запрос GET:
#include <iostream>
#include <cpr.h>
int main(int argc, char** argv) {
auto response = cpr::Get(cpr::Url{"http://httpbin.org/get"});
std::cout << response.text << std::endl;
}
Он поддерживает широкий спектр HTTP-глаголов и опций curl. Здесь больше документации по использованию.
Отказ от ответственности: я хранитель этой библиотеки.
Обновленный ответ за апрель 2020 г.:
Недавно я добился большого успеха с cpp-httplib (как в качестве клиента, так и в качестве сервера). Он зрелый, и его приблизительный однопоточный RPS составляет около 6k.
Более того, есть действительно многообещающий фреймворк, cpv-framework, который может получить около 180 тыс. Запросов в секунду на двух ядрах (и будет хорошо масштабироваться с количеством ядер, потому что он основан на фреймворке Seastar, который поддерживает самые быстрые БД на планета, scylladb).
Однако cpv-framework все еще относительно незрел; поэтому для большинства случаев я настоятельно рекомендую cpp-httplib.
Эта рекомендация заменяет мой предыдущий ответ (8 лет назад).
Вот моя минимальная оболочка вокруг cURL, чтобы можно было просто получить веб-страницу в виде строки. Это полезно, например, для модульного тестирования. Это в основном оболочка RAII вокруг кода C.
Установите "libcurl" на свой компьютер yum install libcurl libcurl-devel
или эквивалент.
Пример использования:
CURLplusplus client;
string x = client.Get("http://google.com");
string y = client.Get("http://yahoo.com");
Реализация класса:
#include <curl/curl.h>
class CURLplusplus
{
private:
CURL* curl;
stringstream ss;
long http_code;
public:
CURLplusplus()
: curl(curl_easy_init())
, http_code(0)
{
}
~CURLplusplus()
{
if (curl) curl_easy_cleanup(curl);
}
std::string Get(const std::string& url)
{
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
ss.str("");
http_code = 0;
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
throw std::runtime_error(curl_easy_strerror(res));
}
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
return ss.str();
}
long GetHttpCode()
{
return http_code;
}
private:
static size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp)
{
return static_cast<CURLplusplus*>(userp)->Write(buffer,size,nmemb);
}
size_t Write(void *buffer, size_t size, size_t nmemb)
{
ss.write((const char*)buffer,size*nmemb);
return size*nmemb;
}
};
Если вам нужно решение C++, вы можете использовать Qt. У него есть класс QHttp, который вы можете использовать.
Вы можете проверить документы:
http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));
Qt также имеет гораздо больше возможностей, которые вы можете использовать в обычном приложении C++.
Вы можете проверить C++ REST SDK (кодовое название "Касабланка"). http://msdn.microsoft.com/en-us/library/jj950081.aspx
С помощью C++ REST SDK вы можете легче подключаться к HTTP-серверам из своего приложения C++.
Пример использования:
#include <iostream>
#include <cpprest/http_client.h>
using namespace web::http; // Common HTTP functionality
using namespace web::http::client; // HTTP client features
int main(int argc, char** argv) {
http_client client("http://httpbin.org/");
http_response response;
// ordinary `get` request
response = client.request(methods::GET, "/get").get();
std::cout << response.extract_string().get() << "\n";
// working with json
response = client.request(methods::GET, "/get").get();
std::cout << "url: " << response.extract_json().get()[U("url")] << "\n";
}
C++ REST SDK - это проект Microsoft для облачной связи клиент-сервер в собственном коде с использованием современного асинхронного C++ API.
libCURL - довольно хороший вариант для вас. В зависимости от того, что вам нужно сделать, учебник должен сказать вам, что вы хотите, особенно для удобной работы. Но, в принципе, вы можете сделать это просто, чтобы увидеть источник страницы:
CURL* c;
c = curl_easy_init();
curl_easy_setopt( c, CURL_URL, "www.google.com" );
curl_easy_perform( c );
curl_easy_cleanup( c );
Я считаю, что это приведет к выводу результата на стандартный вывод. Если вы хотите обработать это вместо этого - что, я полагаю, вы делаете - вам нужно установить CURL_WRITEFUNCTION. Все это описано в уроке по скручиванию, указанном выше.
С этим ответом я ссылаюсь на ответ от Software_Developer. Восстановив код, я обнаружил, что некоторые части устарели (gethostbyname()
) или не обеспечивают обработку ошибок (создание сокетов, отправку чего-либо) для операции.
Следующий код Windows протестирован с 64-битной Visual Studio 2013 и Windows 8.1, а также с 64-битной Windows 7. Он будет нацелен на TCP-соединение IPv4 с веб-сервером www.google.com.
#include <winsock2.h>
#include <WS2tcpip.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main (){
// Initialize Dependencies to the Windows Socket.
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
return -1;
}
// We first prepare some "hints" for the "getaddrinfo" function
// to tell it, that we are looking for a IPv4 TCP Connection.
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // We are targeting IPv4
hints.ai_protocol = IPPROTO_TCP; // We are targeting TCP
hints.ai_socktype = SOCK_STREAM; // We are targeting TCP so its SOCK_STREAM
// Aquiring of the IPv4 address of a host using the newer
// "getaddrinfo" function which outdated "gethostbyname".
// It will search for IPv4 addresses using the TCP-Protocol.
struct addrinfo* targetAdressInfo = NULL;
DWORD getAddrRes = getaddrinfo("www.google.com", NULL, &hints, &targetAdressInfo);
if (getAddrRes != 0 || targetAdressInfo == NULL)
{
cout << "Could not resolve the Host Name" << endl;
system("pause");
WSACleanup();
return -1;
}
// Create the Socket Address Informations, using IPv4
// We dont have to take care of sin_zero, it is only used to extend the length of SOCKADDR_IN to the size of SOCKADDR
SOCKADDR_IN sockAddr;
sockAddr.sin_addr = ((struct sockaddr_in*) targetAdressInfo->ai_addr)->sin_addr; // The IPv4 Address from the Address Resolution Result
sockAddr.sin_family = AF_INET; // IPv4
sockAddr.sin_port = htons(80); // HTTP Port: 80
// We have to free the Address-Information from getaddrinfo again
freeaddrinfo(targetAdressInfo);
// Creation of a socket for the communication with the Web Server,
// using IPv4 and the TCP-Protocol
SOCKET webSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (webSocket == INVALID_SOCKET)
{
cout << "Creation of the Socket Failed" << endl;
system("pause");
WSACleanup();
return -1;
}
// Establishing a connection to the web Socket
cout << "Connecting...\n";
if(connect(webSocket, (SOCKADDR*)&sockAddr, sizeof(sockAddr)) != 0)
{
cout << "Could not connect";
system("pause");
closesocket(webSocket);
WSACleanup();
return -1;
}
cout << "Connected.\n";
// Sending a HTTP-GET-Request to the Web Server
const char* httpRequest = "GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n";
int sentBytes = send(webSocket, httpRequest, strlen(httpRequest),0);
if (sentBytes < strlen(httpRequest) || sentBytes == SOCKET_ERROR)
{
cout << "Could not send the request to the Server" << endl;
system("pause");
closesocket(webSocket);
WSACleanup();
return -1;
}
// Receiving and Displaying an answer from the Web Server
char buffer[10000];
ZeroMemory(buffer, sizeof(buffer));
int dataLen;
while ((dataLen = recv(webSocket, buffer, sizeof(buffer), 0) > 0))
{
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
cout << buffer[i];
i += 1;
}
}
// Cleaning up Windows Socket Dependencies
closesocket(webSocket);
WSACleanup();
system("pause");
return 0;
}
Рекомендации:
Обратите внимание, что для этого не требуется libcurl, Windows.h или WinSock! Нет компиляции библиотек, нет конфигурации проекта и т. Д. У меня есть этот код, работающий в Visual Studio 2017 C++ на Windows 10:
#pragma comment(lib, "urlmon.lib")
#include <urlmon.h>
#include <sstream>
using namespace std;
...
IStream* stream;
//Also works with https URL's - unsure about the extent of SSL support though.
HRESULT result = URLOpenBlockingStream(0, "http://google.com", &stream, 0, 0);
if (result != 0)
{
return 1;
}
char buffer[100];
unsigned long bytesRead;
stringstream ss;
stream->Read(buffer, 100, &bytesRead);
while (bytesRead > 0U)
{
ss.write(buffer, (long long)bytesRead);
stream->Read(buffer, 100, &bytesRead);
}
stream.Release();
string resultString = ss.str();
Я только что понял, как это сделать, так как я хотел простой скрипт доступа к API, библиотеки, такие как libcurl, вызывали у меня всевозможные проблемы (даже когда я следовал инструкциям...), а WinSock слишком низкоуровневый и сложный,
Я не совсем уверен во всем коде чтения IStream (особенно в условиях while - не стесняйтесь исправлять / улучшать), но эй, это работает, без проблем! (Для меня имеет смысл, что, поскольку я использовал блокирующий (синхронный) вызов, это нормально, что bytesRead
будет всегда> 0U, пока поток ( ISequentialStream?) не будет считан, но кто знает.)
См. Также: URL Monikers и Asynchronous Pluggable Protocol Справочник
C++ не предоставляет никакого способа сделать это напрямую. Это будет полностью зависеть от того, какие платформы и библиотеки у вас есть.
В худшем случае вы можете использовать библиотеку boost::asio для установления TCP-соединения, отправки заголовков HTTP (RFC 2616) и непосредственного анализа ответов. Глядя на потребности вашего приложения, это достаточно просто сделать.
Вот некоторый код, который будет работать без необходимости использования какой-либо сторонней библиотеки: сначала определите ваш шлюз, пользователя, пароль и любые другие параметры, которые вам нужно отправить на этот конкретный сервер.
#define USERNAME "user"
#define PASSWORD "your password"
#define GATEWAY "your gateway"
Вот сам код:
HINTERNET hOpenHandle, hResourceHandle, hConnectHandle;
const TCHAR* szHeaders = _T("Content-Type:application/json; charset=utf-8\r\n");
hOpenHandle = InternetOpen(_T("HTTPS"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hOpenHandle == NULL)
{
return false;
}
hConnectHandle = InternetConnect(hOpenHandle,
GATEWAY,
INTERNET_DEFAULT_HTTPS_PORT,
NULL, NULL, INTERNET_SERVICE_HTTP,
0, 1);
if (hConnectHandle == NULL)
{
InternetCloseHandle(hOpenHandle);
return false;
}
hResourceHandle = HttpOpenRequest(hConnectHandle,
_T("POST"),
GATEWAY,
NULL, NULL, NULL, INTERNET_FLAG_SECURE | INTERNET_FLAG_KEEP_CONNECTION,
1);
if (hResourceHandle == NULL)
{
InternetCloseHandle(hOpenHandle);
InternetCloseHandle(hConnectHandle);
return false;
}
InternetSetOption(hResourceHandle, INTERNET_OPTION_USERNAME, (LPVOID)USERNAME, _tcslen(USERNAME));
InternetSetOption(hResourceHandle, INTERNET_OPTION_PASSWORD, (LPVOID)PASSWORD, _tcslen(PASSWORD));
std::string buf;
if (HttpSendRequest(hResourceHandle, szHeaders, 0, NULL, 0))
{
while (true)
{
std::string part;
DWORD size;
if (!InternetQueryDataAvailable(hResourceHandle, &size, 0, 0))break;
if (size == 0)break;
part.resize(size);
if (!InternetReadFile(hResourceHandle, &part[0], part.size(), &size))break;
if (size == 0)break;
part.resize(size);
buf.append(part);
}
}
if (!buf.empty())
{
// Get data back
}
InternetCloseHandle(hResourceHandle);
InternetCloseHandle(hConnectHandle);
InternetCloseHandle(hOpenHandle);
Это должно работать в среде Win32 API.
Вот пример.
C и C++ не имеют стандартной библиотеки для HTTP или даже для сокетных соединений. За эти годы было разработано несколько портативных библиотек. Как уже говорили другие, наиболее широко используемым является libcurl.
Вот список альтернатив libcurl (с веб-сайта libcurl).
Также для Linux это простой HTTP-клиент. Вы можете реализовать свой собственный простой HTTP-клиент GET, но это не сработает, если задействованы аутентификация или перенаправления, или если вам нужно работать за прокси-сервером. Для этих случаев вам нужна полноценная библиотека, такая как libcurl.
Для исходного кода с libcurl это наиболее близко к тому, что вы хотите (у Libcurl есть много примеров). Посмотрите на основную функцию. Содержание html будет скопировано в буфер после успешного подключения. Просто замените parseHtml своей собственной функцией.
Протокол HTTP очень прост, поэтому написать клиент HTTP очень просто. Вот один
https://github.com/pedro-vicente/lib_netsockets
Он использует HTTP GET для получения файла с веб-сервера, и сервер, и файл являются параметрами командной строки. Удаленный файл сохраняется в локальной копии.
Отказ от ответственности: я автор
РЕДАКТИРОВАТЬ: отредактированный URL
Есть ли способ легко сделать HTTP-запрос с C++? В частности, я хочу загрузить содержимое страницы (API) и проверить содержимое, чтобы увидеть, содержит ли оно 1 или 0. Можно ли также загрузить содержимое в строку?
Прежде всего ... Я знаю, что этому вопросу 12 лет. Однако . Ни один из предоставленных ответов не дал примера, который был «простым» без необходимости создания какой-либо внешней библиотеки.
Ниже приведено самое простое решение, которое я мог придумать для извлечения и печати содержимого веб-страницы.
#include <iostream>
#pragma comment(lib, "wininet.lib")
#include <WinSock2.h>
#include <wininet.h>
int main()
{
std::string RESULT{};
const int size = 4096;
char buf[size];
DWORD length;
HINTERNET internet = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL);
if (!internet)
ExitProcess(EXIT_FAILURE);
HINTERNET response = InternetOpenUrlA(internet, "http://www.google.com", NULL, NULL, NULL, NULL);
if (!response) {
InternetCloseHandle(internet);
ExitProcess(EXIT_FAILURE);
}
InternetReadFile(response, buf, size, &length);
InternetCloseHandle(response);
InternetCloseHandle(internet);
std::cout << buf << std::endl;
return 0;
}
Вы можете использовать встроенную библиотеку. Это легкая библиотека только для заголовков. Таким образом, его легко включить в ваш проект, и он не требует компиляции, потому что там нет .cpp
файлы в нем.
Пример запроса от readme.md
из репо:
#include "UrlRequest.hpp"
//...
UrlRequest request;
request.host("api.vk.com");
const auto countryId=1;
const auto count=1000;
request.uri("/method/database.getCities",{
{"lang","ru"},
{"country_id",countryId},
{"count",count},
{"need_all","1"},
});
request.addHeader("Content-Type: application/json");
auto response=std::move(request.perform());
if(response.statusCode()==200){
cout<<"status code = "<<response.statusCode()<<", body = *"<<response.body()<<"*"<<endl;
}else{
cout<<"status code = "<<response.statusCode()<<", description = "<<response.statusDescription()<<endl;
}
Вот некоторый (относительно) простой код C++11, который использует libCURL для загрузки содержимого URL в std::vector<char>
:
http_download.hh
# pragma once
#include <string>
#include <vector>
std::vector<char> download(std::string url, long* responseCode = nullptr);
http_download.cc
#include "http_download.hh"
#include <curl/curl.h>
#include <sstream>
#include <stdexcept>
using namespace std;
size_t callback(void* contents, size_t size, size_t nmemb, void* user)
{
auto chunk = reinterpret_cast<char*>(contents);
auto buffer = reinterpret_cast<vector<char>*>(user);
size_t priorSize = buffer->size();
size_t sizeIncrease = size * nmemb;
buffer->resize(priorSize + sizeIncrease);
std::copy(chunk, chunk + sizeIncrease, buffer->data() + priorSize);
return sizeIncrease;
}
vector<char> download(string url, long* responseCode)
{
vector<char> data;
curl_global_init(CURL_GLOBAL_ALL);
CURL* handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, url.c_str());
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, callback);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data);
curl_easy_setopt(handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
CURLcode result = curl_easy_perform(handle);
if (responseCode != nullptr)
curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, responseCode);
curl_easy_cleanup(handle);
curl_global_cleanup();
if (result != CURLE_OK)
{
stringstream err;
err << "Error downloading from URL \"" << url << "\": " << curl_easy_strerror(result);
throw runtime_error(err.str());
}
return move(data);
}
Если вы ищете клиентскую библиотеку HTTP на C++, которая поддерживается на нескольких платформах (Linux, Windows и Mac) для использования веб-служб Restful. У вас могут быть варианты ниже.
- Сетевая библиотека QT - позволяет приложению отправлять сетевые запросы и получать ответы.
- C++ REST SDK - новая сторонняя HTTP-библиотека с поддержкой PPL.
- Libcurl - вероятно, одна из наиболее часто используемых http-библиотек в мире.
Обычно я бы рекомендовал что-нибудь кроссплатформенное, например cURL, POCO или Qt. Тем не менее, вот пример Windows!
#include <atlbase.h>
#include <msxml6.h>
#include <comutil.h> // _bstr_t
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();
Хотя немного опоздал. Вы можете предпочесть https://github.com/Taymindis/backcurl.
Это позволяет вам выполнять HTTP-вызов на мобильных C++ разработки. Подходит для разработки мобильных игр
bcl::init(); // init when using
bcl::execute<std::string>([&](bcl::Request *req) {
bcl::setOpts(req, CURLOPT_URL , "http://www.google.com",
CURLOPT_FOLLOWLOCATION, 1L,
CURLOPT_WRITEFUNCTION, &bcl::writeContentCallback,
CURLOPT_WRITEDATA, req->dataPtr,
CURLOPT_USERAGENT, "libcurl-agent/1.0",
CURLOPT_RANGE, "0-200000"
);
}, [&](bcl::Response * resp) {
std::string ret = std::string(resp->getBody<std::string>()->c_str());
printf("Sync === %s\n", ret.c_str());
});
bcl::cleanUp(); // clean up when no more using
Все приведенные выше ответы полезны. Мой ответ просто добавляет некоторые дополнения:
- Использование подталкивание зверь, синхронизации пример, асинхронный пример, SSL пример
- Используйте, например , nghttp2 , он поддерживает SSL
- Используйте Facebook proxygen, этот проект включает в себя основные HTTP-абстракции C ++, используемые в Facebook. Он нацелен на высокую производительность и параллелизм. Я рекомендую установить его с помощью vcpkg, иначе вы столкнетесь с проблемами управления зависимостями. Он поддерживает SSL.
И nghttp2, и proxygen стабильны, их можно использовать в продакшене.
Для записи библиотека mongoose cesanta, похоже, также поддерживает это: https://github.com/cesanta/mongoose/blob/6.17/examples/http_client/http_client.c
Вы можете использовать ACE для того, чтобы сделать это:
#include "ace/SOCK_Connector.h"
int main(int argc, ACE_TCHAR* argv[])
{
//HTTP Request Header
char* szRequest = "GET /video/nice.mp4 HTTP/1.1\r\nHost: example.com\r\n\r\n";
int ilen = strlen(szRequest);
//our buffer
char output[16*1024];
ACE_INET_Addr server (80, "example.com");
ACE_SOCK_Stream peer;
ACE_SOCK_Connector connector;
int ires = connector.connect(peer, server);
int sum = 0;
peer.send(szRequest, ilen);
while (true)
{
ACE_Time_Value timeout = ACE_Time_Value(15);
int rc = peer.recv_n(output, 16*1024, &timeout);
if (rc == -1)
{
break;
}
sum += rc;
}
peer.close();
printf("Bytes transffered: %d",sum);
return 0;
}
CppRest SDK от MS - это то, что я только что нашел, и примерно через полчаса мой первый простой вызов веб-службы заработал. По сравнению с другими, упомянутыми здесь, когда я не смог ничего установить даже после нескольких часов поисков, я бы сказал, что это довольно впечатляюще.
https://github.com/microsoft/cpprestsdk
Прокрутите вниз и нажмите "Документация", затем нажмите "Учебное пособие по началу работы", и вы получите простое приложение, работающее в кратчайшие сроки.