有什么方法可以简单地用c++发出HTTP请求吗?具体来说,我想下载一个页面(一个API)的内容,并检查内容,看看它是否包含1或0。是否也可以将内容下载到字符串中?
当前回答
MS的CppRest SDK是我刚刚发现的,大约半小时后,我的第一个简单的web服务调用工作。相比之下,在这里提到的其他地方,我甚至无法安装任何东西,我不得不说,这是相当令人印象深刻的
https://github.com/microsoft/cpprestsdk
向下滚动,点击文档,然后点击入门教程,你将有一个简单的应用程序运行在任何时间。
其他回答
c++没有提供任何直接实现它的方法。这完全取决于你拥有什么样的平台和库。
在最坏的情况下,您可以使用boost::asio库来建立TCP连接,发送HTTP报头(RFC 2616),并直接解析响应。查看您的应用程序需求,这很简单。
有什么方法可以简单地用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(); 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
#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;
}
注意,这并不需要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名称和异步可插协议参考
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教程中介绍了所有这些内容。
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);
}