你如何用 C++ 发出 HTTP 请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1011339/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do you make a HTTP request with C++?
提问by Sam152
Is there any way to easily make a HTTP request with C++? Specifically, I want to download the contents of a page (an API) and check the contents to see if it contains a 1 or a 0. Is it also possible to download the contents into a string?
有什么方法可以轻松地使用 C++ 发出 HTTP 请求?具体来说,我想下载一个页面(一个API)的内容并检查内容以查看它是否包含1或0。是否也可以将内容下载为字符串?
采纳答案by neuro
I had the same problem. libcurlis really complete. There is a C++ wrapper curlppthat might interest you as you ask for a C++ library. neonis another interesting C library that also support WebDAV.
我有同样的问题。libcurl真的很完整。当您要求 C++ 库时,您可能会对C++ 包装器curlpp感兴趣。neon是另一个有趣的 C 库,它也支持WebDAV。
curlpp seems natural if you use C++. There are many examples provided in the source distribution. To get the content of an URL you do something like that (extracted from examples) :
如果您使用 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://www.wikipedia.org"));
string asAskedInQuestion = os.str();
See the examples
directory in curlpp source distribution, there is a lot of more complex cases, as well as a simple complete minimal oneusing curlpp.
看curlpp源码分发examples
目录,有很多更复杂的情况,还有一个简单的完全最小的使用curlpp。
my 2 cents ...
我的 2 美分...
回答by Software_Designer
Windows code:
窗口代码:
#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;
}
Here is a much better implementation:
这是一个更好的实现:
#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);
}
回答by Homer6
Update 2020:I have a new answer that replaces this, now 8-years-old, one: https://stackoverflow.com/a/61177330/278976
2020 年更新:我有一个新答案来取代这个,现在 8 岁了:https: //stackoverflow.com/a/61177330/278976
On Linux, I tried cpp-netlib, libcurl, curlpp, urdl, boost::asio and considered Qt (but turned it down based on the license). All of these were either incomplete for this use, had sloppy interfaces, had poor documentation, were unmaintained or didn't support https.
在 Linux 上,我尝试了 cpp-netlib、libcurl、curlpp、urdl、boost::asio 并考虑了 Qt(但根据许可拒绝了它)。所有这些要么不完整,要么不完整,界面草率,文档差,未维护或不支持 https。
Then, at the suggestion of https://stackoverflow.com/a/1012577/278976, I tried POCO. Wow, I wish I had seen this years ago. Here's an example of making an HTTP GET request with POCO:
然后,在https://stackoverflow.com/a/1012577/278976的建议下,我尝试了 POCO。哇,我真希望我几年前就看到了。这是使用 POCO 发出 HTTP GET 请求的示例:
https://stackoverflow.com/a/26026828/2817595
https://stackoverflow.com/a/26026828/2817595
POCO is free, open source (boost license). And no, I don't have any affiliation with the company; I just really like their interfaces. Great job guys (and gals).
POCO 是免费的、开源的(boost 许可证)。不,我与公司没有任何从属关系;我真的很喜欢他们的界面。干得好伙计们(和女孩们)。
https://pocoproject.org/download.html
https://pocoproject.org/download.html
Hope this helps someone... it took me three days to try all of these libraries out.
希望这对某人有所帮助……我花了三天时间尝试了所有这些库。
回答by huu
There is a newer, less mature curl wrapper being developed called C++ Requests. Here's a simple GET request:
正在开发一种更新的、不太成熟的 curl 包装器,称为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;
}
It supports a wide variety of HTTP verbs and curl options. There's more usage documentation here.
它支持多种 HTTP 动词和 curl 选项。还有更多的使用文档这里。
Disclaimer: I'm the maintainer of this library.
免责声明:我是这个库的维护者。
回答by Mark Lakata
Here is my minimal wrapper around cURL to be able just to fetch a webpage as a string. This is useful, for example, for unit testing. It is basically a RAII wrapper around the C code.
这是我对 cURL 的最小包装,以便能够将网页作为字符串获取。例如,这对于单元测试很有用。它基本上是围绕 C 代码的 RAII 包装器。
Install "libcurl" on your machine yum install libcurl libcurl-devel
or equivalent.
在您的机器yum install libcurl libcurl-devel
或同等设备上安装“libcurl” 。
Usage example:
用法示例:
CURLplusplus client;
string x = client.Get("http://google.com");
string y = client.Get("http://yahoo.com");
Class implementation:
类实现:
#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;
}
};
回答by Marcelo Santos
As you want a C++ solution, you could use Qt. It has a QHttp class you can use.
当你想要一个 C++ 解决方案时,你可以使用Qt。它有一个您可以使用的 QHttp 类。
You can check the docs:
您可以查看文档:
http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));
Qt also has a lot more to it that you could use in a common C++ app.
Qt 还有很多其他功能可以在常见的 C++ 应用程序中使用。
回答by FreeMemory
libCURLis a pretty good option for you. Depending on what you need to do, the tutorialshould tell you what you want, specifically for the easy handle. But, basically, you could do this just to see the source of a page:
libCURL对您来说是一个不错的选择。根据你需要做什么,教程应该告诉你你想要什么,特别是为了容易处理。但是,基本上,您可以这样做只是为了查看页面的来源:
CURL* c;
c = curl_easy_init();
curl_easy_setopt( c, CURL_URL, "www.google.com" );
curl_easy_perform( c );
curl_easy_cleanup( c );
I believe this will cause the result to be printed to stdout. If you want to handle it instead -- which, I assume, you do -- you need to set the CURL_WRITEFUNCTION. All of that is covered in the curl tutorial linked above.
我相信这会导致结果打印到标准输出。如果你想处理它——我假设你这样做——你需要设置 CURL_WRITEFUNCTION。所有这些都包含在上面链接的 curl 教程中。
回答by copperoxide
You may want to check C++ REST SDK(codename "Casablanca"). http://msdn.microsoft.com/en-us/library/jj950081.aspx
您可能需要检查C++ REST SDK(代号“Casablanca”)。http://msdn.microsoft.com/en-us/library/jj950081.aspx
With the C++ REST SDK, you can more easily connect to HTTP servers from your C++ app.
使用 C++ REST SDK,您可以更轻松地从 C++ 应用程序连接到 HTTP 服务器。
Usage example:
用法示例:
#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";
}
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design.
C++ REST SDK 是一个 Microsoft 项目,用于使用现代异步 C++ API 设计以本机代码进行基于云的客户端-服务器通信。
回答by Vinz
With this answer I refer to the answer from Software_Developer. By rebuilding the code I found that some parts are deprecated(gethostbyname()
) or do not provide error handling(creation of sockets, sending something) for an operation.
有了这个答案,我参考了Software_Developer的答案。通过重新构建代码,我发现某些部分已被弃用( gethostbyname()
) 或不为操作提供错误处理(创建套接字、发送某些内容)。
The following windows codeis tested with Visual Studio 2013 and Windows 8.1 64-bit as well as Windows 7 64-bit. It will target an IPv4 TCP Connection with the Web Server of www.google.com.
以下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;
}
References:
参考:
回答by sybreon
C++ does not provide any way to do it directly. It would entirely depend on what platforms and libraries that you have.
C++ 不提供任何直接执行此操作的方法。这完全取决于您拥有哪些平台和库。
At worst case, you can use the boost::asio library to establish a TCP connection, send the HTTP headers (RFC 2616), and parse the responses directly. Looking at your application needs, this is simple enough to do.
在最坏的情况下,您可以使用 boost::asio 库建立 TCP 连接,发送 HTTP 标头 (RFC 2616),并直接解析响应。查看您的应用程序需求,这很简单。