简体   繁体   English

如何使用 C++ 发出 HTTP 请求?

[英]How do you make a HTTP request with C++?

Is there any way to easily make a HTTP request with C++?有什么方法可以轻松地用 C++ 发出 HTTP 请求? 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?具体来说,我想下载页面(API)的内容并检查内容是否包含 1 或 0。是否也可以将内容下载到字符串中?

I had the same problem.我有同样的问题。 libcurl is really complete. libcurl真的很完整。 There is a C++ wrapper curlpp that might interest you as you ask for a C++ library.当您要求 C++ 库时,您可能会对 C++ 包装器curlpp感兴趣。 neon is another interesting C library that also support WebDAV . neon是另一个有趣的 C 库,它也支持WebDAV

curlpp seems natural if you use C++.如果您使用 C++,curlpp 似乎很自然。 There are many examples provided in the source distribution.源代码分发中提供了许多示例。 To get the content of an URL you do something like that (extracted from examples) :要获取 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();

See the examples directory in curlpp source distribution , there is a lot of more complex cases, as well as a simple complete minimal one using curlpp.查看curlpp 源码分发中的examples目录,有很多更复杂的案例,以及使用 curlpp 的简单完整的最小案例。

my 2 cents ...我的 2 美分...

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

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).在 Linux 上,我尝试了 cpp-netlib、libcurl、curlpp、urdl、boost::asio 并考虑了 Qt(但根据许可证拒绝了它)。 All of these were either incomplete for this use, had sloppy interfaces, had poor documentation, were unmaintained or didn't support https.所有这些要么不完整,要么不完整,界面草率,文档差,未维护或不支持 https。

Then, at the suggestion of https://stackoverflow.com/a/1012577/278976 , I tried POCO.然后,在https://stackoverflow.com/a/1012577/278976的建议下,我尝试了 POCO。 Wow, I wish I had seen this years ago.哇,我真希望我几年前就看到了。 Here's an example of making an HTTP GET request with POCO:下面是一个使用 POCO 发出 HTTP GET 请求的示例:

https://stackoverflow.com/a/26026828/2817595 https://stackoverflow.com/a/26026828/2817595

POCO is free, open source (boost license). POCO 是免费的、开源的(增强许可证)。 And no, I don't have any affiliation with the company;不,我与公司没有任何关系; I just really like their interfaces.我真的很喜欢他们的界面。 Great job guys (and gals).干得好家伙(和女孩)。

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.希望这对某人有所帮助……我花了三天时间尝试所有这些库。

There is a newer, less mature curl wrapper being developed called C++ Requests .正在开发一种更新的、不太成熟的 curl 包装器,称为C++ Requests Here's a simple GET request:这是一个简单的 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.它支持多种 HTTP 动词和 curl 选项。 There's more usage documentation here .这里有更多使用文档。

Disclaimer: I'm the maintainer of this library .免责声明:我是这个库的维护者

Updated answer for April, 2020: 2020 年 4 月的更新答案:

I've had a lot of success, recently, with cpp-httplib (both as a client and a server).最近,我使用cpp-httplib (作为客户端和服务器)取得了很大的成功。 It's mature and its approximate, single-threaded RPS is around 6k.它很成熟,其近似的单线程 RPS 约为 6k。

On more of the bleeding edge, there's a really promising framework, cpv-framework , that can get around 180k RPS on two cores (and will scale well with the number of cores because it's based on the seastar framework, which powers the fastest DBs on the planet, scylladb ).在更前沿,有一个非常有前途的框架cpv-framework ,它可以在两个内核上获得大约 180k RPS(并且可以很好地随内核数量扩展,因为它基于seastar框架,它为最快的数据库提供动力星球, scylladb )。

However, cpv-framework is still relatively immature;但是cpv-framework还比较不成熟; so, for most uses, I highly recommend cpp-httplib.因此,对于大多数用途,我强烈推荐 cpp-httplib。

This recommendation replaces my previous answer (8 years ago).此建议取代了我之前的答案(8 年前)。

As you want a C++ solution, you could use Qt .如果您需要 C++ 解决方案,您可以使用Qt It has a QHttp class you can use.它有一个可以使用的 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++ 应用程序中使用。

Here is my minimal wrapper around cURL to be able just to fetch a webpage as a string.这是我对 cURL 的最小包装,它能够将网页作为字符串获取。 This is useful, for example, for unit testing.例如,这对于单元测试很有用。 It is basically a RAII wrapper around the C code.它基本上是 C 代码的 RAII 包装器。

Install "libcurl" on your machine yum install libcurl libcurl-devel or equivalent.在你的机器上安装“libcurl” yum install libcurl libcurl-devel或等效的。

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

You may want to check C++ REST SDK (codename "Casablanca").您可能需要检查C++ REST SDK (代号“Casablanca”)。 http://msdn.microsoft.com/en-us/library/jj950081.aspx 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 设计以本机代码进行基于云的客户端-服务器通信。

libCURL is a pretty good option for you. libCURL对您来说是一个不错的选择。 Depending on what you need to do, the tutorial should tell you what you want, specifically for the easy handle.根据你需要做什么,教程应该告诉你你想要什么,特别是为了容易处理。 But, basically, you could do this just to see the source of a page:但是,基本上,您可以这样做只是为了查看页面的来源:

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.如果你想处理它——我假设你这样做——你需要设置 CURL_WRITEFUNCTION。 All of that is covered in the curl tutorial linked above.所有这些都包含在上面链接的 curl 教程中。

With this answer I refer to the answer from Software_Developer .有了这个答案,我参考了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.通过重建代码,我发现某些部分已被弃用gethostbyname() )或不为操作提供错误处理(创建套接字、发送某些内容)。

The following windows code is tested with Visual Studio 2013 and Windows 8.1 64-bit as well as Windows 7 64-bit.以下Windows 代码使用 Visual Studio 2013 和 Windows 8.1 64 位以及 Windows 7 64 位进行了测试。 It will target an IPv4 TCP Connection with the Web Server of www.google.com.它将以与 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:参考:

Deprecation of gethostbyname 弃用 gethostbyname

Return Value of socket() socket() 的返回值

Return Value of send() send() 的返回值

C++ does not provide any way to do it directly. C++ 没有提供任何直接执行此操作的方法。 It would entirely depend on what platforms and libraries that you have.这完全取决于您拥有的平台和库。

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.在最坏的情况下,您可以使用 boost::asio 库建立 TCP 连接,发送 HTTP 标头 (RFC 2616),并直接解析响应。 Looking at your application needs, this is simple enough to do.查看您的应用程序需求,这很简单。

Here is some code that will work with no need to use any 3rd party library: First define your gateway, user, password and any other parameters you need to send to this specific server.以下是一些无需使用任何第三方库即可工作的代码:首先定义您的网关、用户、密码和您需要发送到此特定服务器的任何其他参数。

#define USERNAME "user"
#define PASSWORD "your password"
#define GATEWAY "your gateway"

Here is the code itself:这是代码本身:

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

That should work on a Win32 API environment.这应该适用于 Win32 API 环境。

Here is an example .这是一个例子

Note that this does not require libcurl, Windows.h, or WinSock!请注意,这不需要 libcurl、Windows.h 或 WinSock! No compilation of libraries, no project configuration, etc. I have this code working in Visual Studio 2017 c++ on Windows 10:无需编译库,无需项目配置等。我在 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();

I just figured out how to do this, as I wanted a simple API access script, libraries like libcurl were causing me all kinds of problems (even when I followed the directions...), and WinSock is just too low-level and complicated.我只是想出了如何做到这一点,因为我想要一个简单的 API 访问脚本,像 libcurl 这样的库给我带来了各种各样的问题(即使我按照指示...),而 WinSock 太低级和复杂了.

I'm not quite sure about all of the IStream reading code (particularly the while condition - feel free to correct/improve), but hey, it works , hassle free!我不太确定所有的IStream阅读代码(特别是 while 条件 - 随时更正/改进),但是嘿,它可以工作,无忧! (It makes sense to me that, since I used a blocking (synchronous) call , this is fine, that bytesRead would always be > 0U until the stream ( ISequentialStream ?) is finished being read, but who knows.) (这对我来说很有意义,因为我使用了阻塞(同步)调用,这很好, bytesRead总是 > 0U 直到流( ISequentialStream ?)被完成读取,但谁知道。)

See also: URL Monikers and Asynchronous Pluggable Protocol Reference另请参阅: URL Monikers 和异步可插入协议参考

The HTTP protocol is very simple, so it is very simple to write a HTTP client. HTTP协议很简单,所以写一个HTTP客户端也很简单。 Here is one这是一个

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

It uses HTTP GET to retrieve a file from a web server, both server and file are command line parameters.它使用 HTTP GET 从 Web 服务器检索文件,服务器和文件都是命令行参数。 The remote file is saved to a local copy.远程文件保存到本地副本。

Disclaimer: I am the author免责声明:我是作者

check http.cc https://github.com/pedro-vicente/lib_netsockets/blob/master/src/http.cc检查 http.cc https://github.com/pedro-vicente/lib_netsockets/blob/master/src/http.cc

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

EDIT: edited URL编辑:编辑的网址

C and C++ don't have a standard library for HTTP or even for socket connections. C 和 C++ 没有用于 HTTP 甚至用于套接字连接的标准库。 Over the years some portable libraries have been developed.多年来,已经开发了一些可移植的库。 The most widely used, as others have said, is libcurl .正如其他人所说,使用最广泛的是libcurl

Here is a list of alternatives to libcurl (coming from the libcurl's web site).这是 libcurl 的替代品列表(来自 libcurl 的网站)。

Also, for Linux, this is a simple HTTP client.此外,对于 Linux, 是一个简单的 HTTP 客户端。 You could implement your own simple HTTP GET client, but this won't work if there are authentication or redirects involved or if you need to work behind a proxy.您可以实现自己的简单 HTTP GET 客户端,但如果涉及身份验证或重定向,或者您需要在代理后面工作,这将不起作用。 For these cases you need a full-blown library like libcurl.对于这些情况,您需要一个成熟的库,例如 libcurl。

For source code with libcurl, this is the closest to what you want (Libcurl has many examples ).对于带有 libcurl 的源代码,是最接近您想要的(Libcurl 有很多示例)。 Look at the main function.看主函数。 The html content will be copied to the buffer, after a successfully connection.成功连接后,html 内容将被复制到缓冲区。 Just replace parseHtml with your own function.只需将 parseHtml 替换为您自己的函数即可。

Here is some (relatively) simple C++11 code that uses libCURL to download a URL's content into a std::vector<char> :这是一些(相对)简单的 C++11 代码,它使用 libCURL 将 URL 的内容下载到std::vector<char>

http_download.hh http_download.hh

# pragma once

#include <string>
#include <vector>

std::vector<char> download(std::string url, long* responseCode = nullptr);

http_download.cc 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;
}

You can use embeddedRest library.您可以使用EmbeddedRest库。 It is lightweight header-only library.它是轻量级的仅头文件库。 So it is easy to include it to your project and it does not require compilation cause there no .cpp files in it.因此很容易将它包含到您的项目中,并且不需要编译,因为其中没有.cpp文件。

Request example from readme.md from repo:从 repo 的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;
}

If you are looking for a HTTP client library in C++ that is supported in multiple platforms (Linux, Windows and Mac) for consuming Restful web services.如果您正在寻找一个支持多个平台(Linux、Windows 和 Mac)的 C++ HTTP 客户端库来使用 Restful Web 服务。 You can have below options.您可以有以下选项。

  1. QT Network Library - Allows the application to send network requests and receive replies QT Network Library - 允许应用程序发送网络请求和接收回复
  2. C++ REST SDK - An emerging third-party HTTP library with PPL support C++ REST SDK - 一个新兴的第三方 HTTP 库,支持 PPL
  3. Libcurl - It is probably one of the most used http lib in the native world. Libcurl - 它可能是原生世界中最常用的 http lib 之一。

Generally I'd recommend something cross-platform like cURL, POCO, or Qt.一般来说,我会推荐一些跨平台的东西,比如 cURL、POCO 或 Qt。 However, here is a Windows example!:但是,这是一个 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();

Although a little bit late.虽然有点晚了。 You may prefer https://github.com/Taymindis/backcurl .您可能更喜欢https://github.com/Taymindis/backcurl

It allows you to do http call on mobile c++ development.它允许您在移动 C++ 开发中进行 http 调用。 Suitable for Mobile game developement适合手机游戏开发

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

All the answers above are helpful.以上所有答案都有帮助。 My answer just adds some additions:我的回答只是添加了一些补充:

  • Use boost beast, sync example, async example, ssl example使用 boost beast、 sync示例、 async示例、 ssl示例
  • Use nghttp2, example , It supports SSL, HTTP/2使用 nghttp2, 例如,它支持 SSL、HTTP/2
  • Use Facebook proxygen , this project comprises the core C++ HTTP abstractions used at Facebook.使用 Facebook proxygen ,该项目包含 Facebook 使用的核心 C++ HTTP 抽象。 It's aimed at high performance and concurrency.它的目标是高性能和并发性。 I recommend installing it with vcpkg or you will struggle with the dependencies management.我建议使用 vcpkg 安装它,否则您将难以管理依赖项。 It supports SSL.它支持 SSL。 It also support some advanced protocols:HTTP/1.1, SPDY/3, SPDY/3.1, HTTP/2, and HTTP/3它还支持一些高级协议:HTTP/1.1、SPDY/3、SPDY/3.1、HTTP/2和HTTP/3

Both nghttp2 and proxygen are stable, can be considered to use in production. nghttp2 和 proxygen 都是稳定的,可以考虑在生产中使用。

Is there any way to easily make a HTTP request with C++?有什么方法可以轻松地用 C++ 发出 HTTP 请求? 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?具体来说,我想下载页面(API)的内容并检查内容是否包含 1 或 0。是否也可以将内容下载到字符串中?

First off ... I know this question is 12 years old.首先...我知道这个问题已经 12 岁了。 However .然而 。 None of the answers provided gave an example that was "simple" without the need to build some external library提供的答案都没有给出一个“简单”的例子,不需要构建一些外部库

Below is the most simple solution I could come up with to retrieve and print the contents of a webpage.以下是我能想到的最简单的解决方案,用于检索和打印网页内容。

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

You can use ACE in order to do so:您可以使用 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 by MS is what I just found and after about 1/2 hour had my first simple web service call working. MS 的 CppRest SDK 是我刚刚发现的,大约 1/2 小时后,我的第一个简单的 Web 服务调用开始工作。 Compared that to others mentioned here where I was not able to get anything even installed after hours of looking, I'd say it is pretty impressive与这里提到的其他人相比,即使经过数小时的查看,我什至无法安装任何东西,我会说它非常令人印象深刻

https://github.com/microsoft/cpprestsdk https://github.com/microsoft/cpprestsdk

Scroll down and click on Documentation, then click on Getting Started Tutorial and you will have a simple app running in no time.向下滚动并单击文档,然后单击入门教程,您将立即运行一个简单的应用程序。

作为记录,cesanta 的猫鼬库似乎也支持这一点: https ://github.com/cesanta/mongoose/blob/6.17/examples/http_client/http_client.c

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM