Sam*_*152 238 c++ httprequest
有没有办法轻松用C++发出HTTP请求?具体来说,我想下载页面的内容(API)并检查内容,看它是否包含1或0.是否也可以将内容下载到字符串中?
neu*_*uro 229
我有同样的问题.libcurl非常完整.当你要求一个C++库时,有一个C++包装器curlpp可能会让你感兴趣.neon是另一个有趣的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://www.wikipedia.org"));
string asAskedInQuestion = os.str();
Run Code Online (Sandbox Code Playgroud)
查看curlpp源代码分发中的examples目录,有很多更复杂的情况,以及使用curlpp 的简单完整的最小情况.
我的2美分......
Sof*_*ner 112
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;
}
Run Code Online (Sandbox Code Playgroud)
这是一个更好的实现:
#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);
}
Run Code Online (Sandbox Code Playgroud)
Hom*_*er6 38
在Linux上,我尝试了cpp-netlib,libcurl,curlpp,urdl,boost :: asio并考虑了Qt(但根据许可证将其关闭).所有这些对于这种用途来说都是不完整的,有稀疏的接口,文档很差,没有维护或不支持https.
然后,根据/sf/answers/70880421/的建议,我尝试了POCO.哇,我希望我多年前见过.以下是发出HTTP GET请求的示例:
http://xjia.heroku.com/2011/09/10/learning-poco-get-with-http/
POCO是免费的,开源的(增强许可证).不,我与公司没有任何关系; 我真的很喜欢他们的界面.干得好(和女孩们).
http://pocoproject.org/download/index.html
希望这有助于某人...我花了三天时间尝试所有这些库.
huu*_*huu 31
有一种更新的,不太成熟的卷曲包装器正在开发,称为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;
}
Run Code Online (Sandbox Code Playgroud)
它支持各种HTTP动词和卷曲选项.还有更多的使用文档这里.
免责声明:我是这个库的维护者.
Fre*_*ory 16
libCURL对你来说是个不错的选择.根据您的需要,教程应该告诉您您想要什么,特别是为了方便处理.但是,基本上,你可以这样做只是为了看到页面的来源:
CURL* c;
c = curl_easy_init();
curl_easy_setopt( c, CURL_URL, "www.google.com" );
curl_easy_perform( c );
curl_easy_cleanup( c );
Run Code Online (Sandbox Code Playgroud)
我相信这会导致结果打印到标准输出.如果你想要处理它 - 我认为你做了 - 你需要设置CURL_WRITEFUNCTION.所有这些都包含在上面链接的卷曲教程中.
Mar*_*tos 16
如您所希望的C++解决方案,您可以使用Qt.它有一个你可以使用的QHttp类.
您可以查看文档:
http->setHost("qt.nokia.com");
http->get(QUrl::toPercentEncoding("/index.html"));
Run Code Online (Sandbox Code Playgroud)
Qt还有更多可用于常见C++应用程序的内容.
Mar*_*ata 16
这是我在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");
Run Code Online (Sandbox Code Playgroud)
课程实施:
#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;
}
};
Run Code Online (Sandbox Code Playgroud)
Hom*_*er6 15
2020 年 4 月的更新答案:
最近,我使用cpp-httplib(作为客户端和服务器)取得了很多成功。它已经成熟,其近似的单线程 RPS 约为 6k。
在更多前沿领域,有一个非常有前途的框架cpv-framework,它可以在两个内核上获得大约 180k RPS(并且可以随着内核数量的增加而很好地扩展,因为它基于seastar框架,该框架支持最快的数据库行星,scylladb)。
但是cpv-framework还比较不成熟;因此,对于大多数用途,我强烈推荐 cpp-httplib。
这个建议取代了我之前的回答(8 年前)。
小智 12
您可能需要检查C++ REST SDK(代号为"Casablanca").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";
}
Run Code Online (Sandbox Code Playgroud)
C++ REST SDK是一个Microsoft项目,使用现代异步C++ API设计在本机代码中进行基于云的客户端 - 服务器通信.
Vin*_*inz 10
有了这个答案,我将参考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;
}
Run Code Online (Sandbox Code Playgroud)
参考文献:
C++没有提供任何直接的方法.它完全取决于您拥有的平台和库.
在最坏的情况下,您可以使用boost :: asio库建立TCP连接,发送HTTP头(RFC 2616),并直接解析响应.看看您的应用程序需求,这很简单.
以下是一些无需使用任何 3rd 方库即可工作的代码:首先定义您的网关、用户、密码和您需要发送到此特定服务器的任何其他参数。
#define USERNAME "user"
#define PASSWORD "your password"
#define GATEWAY "your gateway"
Run Code Online (Sandbox Code Playgroud)
这是代码本身:
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);
Run Code Online (Sandbox Code Playgroud)
这应该适用于 Win32 API 环境。
这是一个例子。
请注意,这不需要 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();
Run Code Online (Sandbox Code Playgroud)
我只是想出了如何做到这一点,因为我想要一个简单的 API 访问脚本,像 libcurl 这样的库给我带来了各种各样的问题(即使我按照指示...),而 WinSock 太低级和复杂.
我不太确定所有的IStream阅读代码(尤其是 while 条件 - 随时纠正/改进),但是嘿,它有效,无忧!(这对我来说很有意义,因为我使用了阻塞(同步)调用,这很好,bytesRead在流(ISequentialStream?)完成读取之前,它总是> 0U ,但谁知道。)
C 和 C++ 没有用于 HTTP 甚至套接字连接的标准库。多年来,已经开发了一些便携式库。正如其他人所说,使用最广泛的是libcurl。
以下是libcurl 的替代品列表(来自 libcurl 的网站)。
另外,对于 Linux,这是一个简单的 HTTP 客户端。您可以实现自己的简单 HTTP GET 客户端,但如果涉及身份验证或重定向,或者需要在代理后面工作,则这将不起作用。对于这些情况,您需要一个成熟的库,例如 libcurl。
对于带有 libcurl 的源代码,这是最接近您想要的(Libcurl 有很多示例)。看一下主要功能。连接成功后,html 内容将被复制到缓冲区。只需将 parseHtml 替换为您自己的函数即可。
HTTP协议很简单,所以写一个HTTP客户端就很简单了。这是一个
https://github.com/pedro-vicente/lib_netsockets
它使用 HTTP GET 从 Web 服务器检索文件,服务器和文件都是命令行参数。远程文件保存到本地副本。
免责声明:我是作者
检查 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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:编辑的网址