如何使用c++进行HTTP请求?

有什么方法可以简单地用c++发出HTTP请求吗?具体来说,我想下载一个页面(一个API)的内容,并检查内容,看看它是否包含1或0。是否也可以将内容下载到字符串中?

699510 次浏览

c++没有提供任何直接实现它的方法。这完全取决于你拥有什么样的平台和库。

在最坏的情况下,您可以使用boost::asio库来建立TCP连接,发送HTTP报头(RFC 2616),并直接解析响应。查看您的应用程序需求,这很简单。

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。上面链接的curl教程中介绍了所有这些内容。

C和c++没有用于HTTP甚至套接字连接的标准库。多年来,一些便携式图书馆已经被开发出来。正如其他人所说,最广泛使用的是libcurl

下面是libcurl的替代品列表(来自libcurl的网站)。

同样,对于Linux, 是一个简单的HTTP客户端。您可以实现自己的简单HTTP GET客户端,但如果涉及到身份验证或重定向,或者需要在代理后工作,则这将不起作用。对于这些情况,您需要像libcurl这样成熟的库。

对于libcurl的源代码,是最接近你想要的(libcurl有许多例子)。看看主要功能。成功连接后,html内容将被复制到缓冲区。只需用自己的函数替换parseHtml即可。

我也有同样的问题。libcurl是真正完整的。有一个c++包装器curlpp,你可能会感兴趣,当你要求一个c++库。霓虹灯是另一个有趣的C库,它也支持WebDAV

如果你使用c++,

curlpp看起来很自然。源代码发行版中提供了许多示例。 要获取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://example.com"));


string asAskedInQuestion = os.str();

查看Curlpp源分布中的examples目录,有很多更复杂的情况,以及一个使用curlpp的简单完全最小1

我的2美分…

如果你想要c++解决方案,你可以使用Qt。它有一个可以使用的QHttp类。

你可以检查文档:

http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));

Qt还有很多可以在普通c++应用程序中使用的功能。

2020年更新:我有一个新的答案来取代这个,现在已经8年了,一个:https://stackoverflow.com/a/61177330/278976

在Linux上,我尝试了cppp -netlib、libcurl、curlpp、urdl、boost::asio,并考虑过Qt(但基于许可证拒绝了它)。所有这些都不是不完整的,有草率的界面,有糟糕的文档,没有维护或不支持https。

然后,在https://stackoverflow.com/a/1012577/278976的建议下,我尝试了POCO。哇,我真希望几年前就能看到。下面是一个使用POCO进行HTTP GET请求的示例:

https://stackoverflow.com/a/26026828/2817595 < a href = " https://stackoverflow.com/a/26026828/2817595 " > < / >

POCO是免费的、开源的(boost许可证)。不,我和这家公司没有任何关系;我真的很喜欢他们的界面。干得好,伙计们(和姑娘们)。

https://pocoproject.org/download.html

希望这能帮助到某人…我花了三天时间把所有这些库都试了一遍。

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://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);
}

你可能想检查c++ rest SDK(代号“卡萨布兰卡”)。http://msdn.microsoft.com/en-us/library/jj950081.aspx

使用c++ REST SDK,您可以更轻松地从c++应用程序连接到HTTP服务器。

使用的例子:

#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是微软的一个项目,用于使用现代异步c++ API设计的本地代码进行基于云的客户端-服务器通信。

一般来说,我会推荐一些跨平台的工具,比如cURL、POCO或Qt。:

#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();

下面是一些(相对)简单的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 data;
}

这是我关于cURL的最小包装器,它能够以字符串的形式获取网页。例如,这对于单元测试很有用。它基本上是一个围绕C代码的RAII包装器。

在你的机器上安装"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;
}
};

对于这个答案,我引用答案来自Software_Developer。通过重建代码,我发现一些部分是弃用 (gethostbyname())或不提供错误处理(创建套接字,发送一些东西)的操作。

下面的windows代码是用Visual Studio 2013和Windows 8.1 64位以及Windows 7 64位进行测试的。它将目标与www.google.com的Web服务器的IPv4 TCP连接。

#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;
}

引用:

gethostbyname的弃用

socket()的返回值

send()返回值

你可以使用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;
}

有一个更新的,不太成熟的卷曲包装器正在开发,称为c++的请求。下面是一个简单的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选项。还有更多使用文档在这里

免责声明:我是这个库的维护者

你可以使用embeddedRest库。它是一个轻量级的头文件库。所以很容易将它包含到你的项目中,而且不需要编译,因为里面没有.cpp文件。

readme.md从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;
}

HTTP协议非常简单,所以写HTTP客户端非常简单。 这里有一个

https://github.com/pedro-vicente/lib_netsockets

它使用HTTP GET从web服务器检索文件,服务器和文件都是命令行参数。远程文件保存为本地副本。

声明:我是作者

< p >检查http.cc https://github.com/pedro-vicente/lib_netsockets/blob/master/src/http.cc < / p >
int http_client_t::get(const char *path_remote_file)
{
char buf_request[1024];


//construct request message using class input parameters
sprintf(buf_request, "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path_remote_file, m_server_ip.c_str());


//send request, using built in tcp_client_t socket
if (this->write_all(buf_request, (int)strlen(buf_request)) < 0)
{
return -1;
}

编辑:编辑URL

虽然有点晚了。你可能更喜欢https://github.com/Taymindis/backcurl

它允许你在移动c++开发上进行http调用。适合手机游戏开发

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

注意,这并不需要libcurl, Windows.h,或WinSock!没有编译库,没有项目配置,等等。我有这段代码在Windows 10上的Visual Studio 2017 c++中工作:

#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名称和异步可插协议引用

下面是一些不需要使用任何第三方库的代码: 首先定义您的网关,用户,密码和任何其他参数,您需要发送到这个特定的服务器
#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环境中工作。

这是一个例子

如果您正在寻找在多个平台(Linux, Windows和Mac)支持的c++中的HTTP客户端库,以使用Restful web服务。您可以有以下选项。

  1. 允许应用程序发送网络请求并接收回复
  2. c++ rest SDK -一个新兴的支持PPL的第三方HTTP库
  3. Libcurl -它可能是本地世界中使用最多的http库之一。

2020年4月的最新答案:

最近,我用cpp-httplib(作为客户端和服务器)取得了很多成功。它是成熟的,它的近似,单线程RPS约为6k。

在更前沿的领域,有一个非常有前途的框架cpv-framework,它可以在两个核上获得大约180k RPS(并且可以很好地扩展核数,因为它基于盛世达框架,它为地球上最快的db提供动力,scylladb)。

但是cpv-framework还比较不成熟;所以,对于大多数用途,我强烈推荐cppp -httplib。

此建议取代我之前的回答(8年前)。

MS的CppRest SDK是我刚刚发现的,大约半小时后,我的第一个简单的web服务调用工作。相比之下,在这里提到的其他地方,我甚至无法安装任何东西,我不得不说,这是相当令人印象深刻的

https://github.com/microsoft/cpprestsdk

向下滚动,点击文档,然后点击入门教程,你将有一个简单的应用程序运行在任何时间。

以上所有的答案都是有帮助的。我的回答只是补充了一些内容:

  • 使用boost beast, 同步的例子,异步的例子,ssl的例子
  • 使用nghttp2, 例子,它支持SSL, HTTP/2
  • 使用Facebook proxygen,这个项目包括在Facebook上使用的核心c++ HTTP抽象。它的目标是高性能和并发性。我建议用vcpkg安装它,否则你会在依赖项管理上遇到困难。支持SSL。它还支持一些高级协议:HTTP/1.1、SPDY/3、SPDY/3.1、HTTP/2和HTTP/3

nghttp2和prooxygen都是稳定的,可以考虑在生产中使用。

有什么方法可以简单地用c++发出HTTP请求吗?具体来说,我想下载一个页面(一个API)的内容,并检查内容,看看它是否包含1或0。是否也可以将内容下载到字符串中?

首先……我知道这个问题已经有12年了。然而。没有一个答案给出的例子是“简单”的。不需要构建一些外部库

下面是我能想到的检索和打印网页内容的最简单的解决方案。

关于下面示例中使用的函数的一些文档

// wininet lib:
https://learn.microsoft.com/en-us/windows/win32/api/wininet/
// wininet->internetopena();
https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopena
// wininet->intenetopenurla();
. https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetopenurla
// wininet->internetreadfile();
. txt https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetreadfile
// wininet->internetclosehandle();
https://learn.microsoft.com/en-us/windows/win32/api/wininet/nf-wininet-internetclosehandle < / p >

#include <iostream>


#include <WinSock2.h>
#include <wininet.h>
#pragma comment(lib, "wininet.lib")


int main()
{
//  ESTABLISH SOME LOOSE VARIABLES
const int size = 4096;
char buf[size];
DWORD length;


//  ESTABLISH CONNECTION TO THE INTERNET
HINTERNET internet = InternetOpenA("Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL);
if (!internet)
ExitProcess(EXIT_FAILURE);  //  Failed to establish connection to internet, Exit


//  ATTEMPT TO CONNECT TO WEBSITE "google.com"
HINTERNET response = InternetOpenUrlA(internet, "http://www.google.com", NULL, NULL, NULL, NULL);
if (!response) {
//  CONNECTION TO "google.com" FAILED
InternetCloseHandle(internet);  //  Close handle to internet
ExitProcess(EXIT_FAILURE);
}


//  READ CONTENTS OF WEBPAGE IN HTML FORMAT
if (!InternetReadFile(response, buf, size, &length)) {
//  FAILED TO READ CONTENTS OF WEBPAGE
//  Close handles and Exit
InternetCloseHandle(response);                      //  Close handle to response
InternetCloseHandle(internet);                      //  Close handle to internet
ExitProcess(EXIT_FAILURE);
}
    

//  CLOSE HANDLES AND OUTPUT CONTENTS OF WEBPAGE
InternetCloseHandle(response);                      //  Close handle to response
InternetCloseHandle(internet);                      //  Close handle to internet
std::cout << buf << std::endl;
return 0;
}