Existe alguma maneira de fazer facilmente uma solicitação HTTP com C ++? Especificamente, quero baixar o conteúdo de uma página (uma API) e verificar o conteúdo para ver se contém 1 ou 0. Também é possível fazer o download do conteúdo em uma string?
Existe alguma maneira de fazer facilmente uma solicitação HTTP com C ++? Especificamente, quero baixar o conteúdo de uma página (uma API) e verificar o conteúdo para ver se contém 1 ou 0. Também é possível fazer o download do conteúdo em uma string?
Respostas:
Eu tive o mesmo problema. libcurl é realmente completo. Há um curlpp do wrapper C ++ que pode lhe interessar quando você solicita uma biblioteca C ++. neon é outra biblioteca C interessante que também suporta WebDAV .
O curlpp parece natural se você usa C ++. Existem muitos exemplos fornecidos na distribuição de origem. Para obter o conteúdo de um URL, faça algo assim (extraído de exemplos):
// 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();
Veja o examples
diretório na distribuição de fontes curlpp , existem muitos casos mais complexos, bem como um mínimo completo e simples usando curlpp.
meus 2 centavos ...
os << myRequest.perform();
por myRequest.setOpt( new curlpp::options::WriteStream( &os ) ); myRequest.perform();
deu resultados. Certifique-se de não usar http://example.com
, isso retornará uma página vazia. Melhor uso, por exemplo http://www.wikipedia.org
.
Código do 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;
}
Aqui está uma implementação muito melhor:
#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://stackoverflow.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);
}
GET / HTTP/1.1.1/... etc
)? Como descubro como formatar o que envio?
Atualização 2020: Tenho uma nova resposta que substitui essa, agora com 8 anos, uma: https://stackoverflow.com/a/61177330/278976
No Linux, tentei cpp-netlib, libcurl, curlpp, urdl, boost :: asio e considerei o Qt (mas o diminuí com base na licença). Todos eles estavam incompletos para esse uso, tinham interfaces desleixadas, documentação deficiente, não eram mantidos ou não eram compatíveis com https.
Então, por sugestão de https://stackoverflow.com/a/1012577/278976 , tentei o POCO. Uau, eu gostaria de ter visto isso anos atrás. Aqui está um exemplo de como fazer uma solicitação HTTP GET com o POCO:
https://stackoverflow.com/a/26026828/2817595
O POCO é gratuito, de código aberto (licença de reforço). E não, eu não tenho nenhuma afiliação com a empresa; Eu realmente gosto das interfaces deles. Excelente trabalho pessoal (e moças).
https://pocoproject.org/download.html
Espero que isso ajude alguém ... Levei três dias para experimentar todas essas bibliotecas.
Está sendo desenvolvido um wrapper de ondulação mais novo e menos maduro, chamado C ++ Requests . Aqui está uma solicitação GET simples:
#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;
}
Ele suporta uma ampla variedade de verbos HTTP e opções de ondulação. Há mais documentação de uso aqui .
Disclaimer: Eu sou o mantenedor desta biblioteca .
Aqui está meu invólucro mínimo em torno do cURL para conseguir apenas uma página da Web como uma string. Isso é útil, por exemplo, para testes de unidade. É basicamente um wrapper RAII em torno do código C.
Instale "libcurl" na sua máquina yum install libcurl libcurl-devel
ou equivalente.
Exemplo de uso:
CURLplusplus client;
string x = client.Get("http://google.com");
string y = client.Get("http://yahoo.com");
Implementação de classe:
#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;
}
};
libCURL é uma opção muito boa para você. Dependendo do que você precisa fazer, o tutorial deve dizer o que você deseja, especificamente para o manuseio fácil. Mas, basicamente, você poderia fazer isso apenas para ver a fonte de uma página:
CURL* c;
c = curl_easy_init();
curl_easy_setopt( c, CURL_URL, "www.google.com" );
curl_easy_perform( c );
curl_easy_cleanup( c );
Acredito que isso fará com que o resultado seja impresso em stdout. Se você quiser lidar com isso - o que, eu suponho, você precisa - você precisará definir o CURL_WRITEFUNCTION. Tudo isso é abordado no tutorial de ondulação vinculado acima.
Como você deseja uma solução C ++, você pode usar o Qt . Tem uma classe QHttp que você pode usar.
Você pode verificar os documentos :
http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));
O Qt também possui muito mais do que você poderia usar em um aplicativo C ++ comum.
QNetworkAccessManager
está documentado desde o quarto trimestre; e no Qt 4.8 diz: QHttp - This class is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.
Acho que ainda está disponível, se você ignorar os avisos preteridos.
Convém verificar o C ++ REST SDK (codinome "Casablanca"). http://msdn.microsoft.com/en-us/library/jj950081.aspx
Com o C ++ REST SDK, você pode conectar-se mais facilmente a servidores HTTP a partir do seu aplicativo C ++.
Exemplo de uso:
#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";
}
O C ++ REST SDK é um projeto da Microsoft para comunicação cliente-servidor baseado em nuvem em código nativo usando um design moderno de API C ++ assíncrona.
Com esta resposta, refiro-me à resposta do Software_Developer . Ao reconstruir o código, descobri que algumas partes estão obsoletas ( gethostbyname()
) ou não fornecem tratamento de erros (criação de sockets, enviando algo) para uma operação.
O código do Windows a seguir é testado com o Visual Studio 2013 e Windows 8.1 de 64 bits, além do Windows 7 de 64 bits. Ele terá como alvo uma conexão TCP IPv4 com o servidor Web de 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;
}
Referências:
Descontinuação de gethostbyname
O C ++ não fornece nenhuma maneira de fazê-lo diretamente. Isso dependeria inteiramente de quais plataformas e bibliotecas você possui.
Na pior das hipóteses, você pode usar a biblioteca boost :: asio para estabelecer uma conexão TCP, enviar os cabeçalhos HTTP (RFC 2616) e analisar as respostas diretamente. Olhando para as necessidades de sua aplicação, isso é simples o suficiente.
Aqui está um código que funcionará sem a necessidade de usar nenhuma biblioteca de terceiros: primeiro defina seu gateway, usuário, senha e quaisquer outros parâmetros que você precisa enviar para esse servidor específico.
#define USERNAME "user"
#define PASSWORD "your password"
#define GATEWAY "your gateway"
Aqui está o próprio código:
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);
Isso deve funcionar em um ambiente de API do Win32.
Aqui está um exemplo .
InternetConnect
retorna nulo quando o URL completo é fornecido, mas retorna um valor não nulo quando apenas o nome do domínio é fornecido. Então, quando / onde uso o URL completo para obter a página que quero baixar?
Resposta atualizada para abril de 2020:
Recentemente, tive muito sucesso com o cpp-activationplib (como cliente e servidor). É maduro e seu RPS aproximado e de thread único é de cerca de 6k.
Em termos mais avançados , há uma estrutura realmente promissora, a cpv-framework , que pode chegar a cerca de 180k RPS em dois núcleos (e escalará bem com o número de núcleos porque é baseada na estrutura seastar , que fornece os DBs mais rápidos em o planeta, scylladb ).
No entanto, o cpv-framework ainda é relativamente imaturo; portanto, para a maioria dos usos, eu recomendo o cpp-activationplib.
Esta recomendação substitui a minha resposta anterior (há 8 anos).
C e C ++ não têm uma biblioteca padrão para HTTP ou mesmo para conexões de soquete. Ao longo dos anos, algumas bibliotecas portáteis foram desenvolvidas. O mais amplamente usado, como outros já disseram, é o libcurl .
Aqui está uma lista de alternativas para libcurl (provenientes do site da libcurl).
Além disso, para Linux, isso é um cliente HTTP simples. Você pode implementar seu próprio cliente HTTP GET simples, mas isso não funcionará se houver autenticação ou redirecionamento envolvido ou se você precisar trabalhar atrás de um proxy. Para esses casos, você precisa de uma biblioteca completa como a libcurl.
Para código fonte com libcurl, este é o mais próximo do que você deseja (o Libcurl tem muitos exemplos ). Veja a função principal. O conteúdo html será copiado para o buffer, após uma conexão bem-sucedida. Apenas substitua parseHtml por sua própria função.
Você pode usar a biblioteca embeddedRest . É uma biblioteca leve apenas de cabeçalho. Portanto, é fácil incluí-lo no seu projeto e não requer compilação, porque não há.cpp
arquivos nele.
Solicite um exemplo readme.md
do repo:
#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;
}
netdb.h
etc, então eu gostaria de algumas sim ajuda
#ifdef _WIN32
e adicionar um código específico do Windows. Veja aqui - não há muita diferença entre soquetes unix e soquetes para janelas. Vejo duas diferenças principais: 1) chamar WSAStartup
primeiro e 2) usar closesocket
, em vez declose
O protocolo HTTP é muito simples, portanto, é muito simples escrever um cliente HTTP. Aqui está um
https://github.com/pedro-vicente/lib_netsockets
Ele usa HTTP GET para recuperar um arquivo de um servidor da Web, servidor e arquivo são parâmetros de linha de comando. O arquivo remoto é salvo em uma cópia local.
Disclaimer: Eu sou o autor
EDIT: URL editado
Observe que isso não requer libcurl, Windows.h ou WinSock! Nenhuma compilação de bibliotecas, nenhuma configuração de projeto etc. Eu tenho esse código trabalhando no Visual Studio 2017 c ++ no 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();
Eu acabei de descobrir como fazer isso, como queria um script de acesso à API simples, bibliotecas como a libcurl estavam me causando todos os tipos de problemas (mesmo quando eu segui as instruções ...), e o WinSock é de nível muito baixo e complicado demais. .
Não tenho muita certeza sobre todo o código de leitura do IStream (particularmente a condição while - sinta-se à vontade para corrigir / melhorar), mas, ei, funciona , sem complicações! (Faz sentido para mim que, desde que eu usei uma chamada de bloqueio (síncrona) , tudo bem, isso bytesRead
sempre seria> 0U até que o fluxo ( ISequentialStream ?) Termine de ser lido, mas quem sabe.
Consulte também: Referência de apelidos de URL e protocolo de conexão assíncrona
Aqui está um código C ++ 11 (relativamente) simples que usa libCURL para baixar o conteúdo de uma URL em std::vector<char>
:
# pragma once
#include <string>
#include <vector>
std::vector<char> download(std::string url, long* responseCode = nullptr);
#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);
}
Geralmente, eu recomendaria algo entre plataformas, como cURL, POCO ou Qt. No entanto, aqui está um exemplo do 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();
Se você estiver procurando por uma biblioteca cliente HTTP em C ++ suportada em várias plataformas (Linux, Windows e Mac) para consumir serviços da Web Restful. Você pode ter as opções abaixo.
Embora um pouco atrasado. Você pode preferir https://github.com/Taymindis/backcurl .
Ele permite que você faça chamadas http no desenvolvimento de c ++ móvel. Apropriado para o desenvolvimento de jogos para dispositivos móveis
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
Você pode usar o ACE para fazer isso:
#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;
}