目录

C++ 实现HTTP GET和POST

C++ 一个简单的实现HTTP GET和POST请求的类

最近有个项目需要用到HTTP GET和POST请求,但是网上没有找到特别好用的类,就自己写了一个。

这个类除了实现了GET和POST请求,还有对Response中的头部分信息的简单处理。


主要参考

代码主要参考 [ C++ 实现 发送HTTP Get/Post请求 ]。

头文件

头文件很简单:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*! @file
**********************************************************************
<PRE>
模块名       : 
文件名       : HttpRequest.h
相关文件     : HttpRequest.cpp
文件实现功能 : Http 请求
作者         : Song
版本         : 1.0
----------------------------------------------------------------------
备注         : 
----------------------------------------------------------------------
修改记录     : 
日 期        版本   修改人                 修改内容 
2018/4/10    1.0    Song                    创建
</PRE>
**********************************************************************

* 版权所有(c) 2018-2019, 保留所有权利

*********************************************************************/
#pragma once
#include <string>
#include <vector>

class HttpRequest
{
public:
    HttpRequest(const std::string& ip, int port);
    ~HttpRequest(void);

    // Http GET请求
    std::string HttpGet(std::string req);

    // Http POST请求
    std::string HttpPost(std::string req, std::string data);

    // 合成JSON字符串
    static std::string genJsonString(std::string key, int value);

    // 分割字符串
    static std::vector<std::string> split(const std::string &s, const std::string &seperator);

    // 根据key从Response获取Header中的内容
    static std::string getHeader(std::string respose, std::string key);

private:
    std::string         m_ip;
    int             m_port;
};

CPP文件

CPP文件:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*! @file
**********************************************************************
<PRE>
模块名       : 
文件名       : HttpRequest.cpp
相关文件     : HttpRequest.h
文件实现功能 : Http 请求
作者         : Song
版本         : 1.0
----------------------------------------------------------------------
备注         : 
----------------------------------------------------------------------
修改记录     : 
日 期        版本   修改人                 修改内容 
2018/4/10    1.0    Song                    创建
</PRE>
**********************************************************************

* 版权所有(c) 2018-2019, 保留所有权利

*********************************************************************/
#include "HttpRequest.h"
#include <WinSock.h>
#include <iostream>

#pragma comment(lib, "ws2_32.lib")

HttpRequest::HttpRequest(const std::string& ip, int port) : m_ip(ip), m_port(port)
{
}


HttpRequest::~HttpRequest(void)
{
}

// Http GET请求
std::string HttpRequest::HttpGet(std::string req)
{
    std::string ret = ""; // 返回Http Response
    try
    {
        // 开始进行socket初始化
        WSADATA wData;  
        ::WSAStartup(MAKEWORD(2, 2), &wData);  

        SOCKET clientSocket = socket(AF_INET, 1, 0);
        struct sockaddr_in ServerAddr = {0};
        ServerAddr.sin_addr.s_addr = inet_addr(m_ip.c_str());  
        ServerAddr.sin_port = htons(m_port);
        ServerAddr.sin_family = AF_INET; 
        int errNo = connect(clientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));  
        if(errNo == 0)  
        {  
            //  "GET /[req] HTTP/1.1\r\n"  
            //  "Connection:Keep-Alive\r\n"
            //  "Accept-Encoding:gzip, deflate\r\n"  
            //  "Accept-Language:zh-CN,en,*\r\n"
            //  "User-Agent:Mozilla/5.0\r\n\r\n";
            std::string strSend = " HTTP/1.1\r\n"
                "Cookie:16888\r\n\r\n";
            strSend = "GET " + req + strSend;

            // 发送
            errNo = send(clientSocket, strSend.c_str(), strSend.length(), 0);
            if(errNo > 0)  
            {  
                //cout << "发送成功" << endl;
            }
            else
            {
                std::cout << "errNo:" << errNo << std::endl; 
                return ret;
            }

            // 接收
            char bufRecv[3069] = {0};
            errNo = recv(clientSocket, bufRecv, 3069, 0);
            if(errNo > 0)  
            {  
                ret = bufRecv;// 如果接收成功,则返回接收的数据内容  
            }
            else
            {
                std::cout << "errNo:" << errNo << std::endl; 
                return ret;
            }
        }  
        else  
        {  
            errNo = WSAGetLastError();  
            std::cout << "errNo:" << errNo << std::endl; 
        }  
        // socket环境清理
        ::WSACleanup();  
    }
    catch (...)
    {
        return "";
    }
    return ret;
}

// Http POST请求
std::string HttpRequest::HttpPost(std::string req, std::string data)
{
    std::string ret = ""; // 返回Http Response
    try
    {
        // 开始进行socket初始化;
        WSADATA wData;  
        ::WSAStartup(MAKEWORD(2, 2), &wData);  

        SOCKET clientSocket = socket(AF_INET, 1, 0);
        struct sockaddr_in ServerAddr = {0}; 
        ServerAddr.sin_addr.s_addr = inet_addr(m_ip.c_str());  
        ServerAddr.sin_port = htons(m_port);
        ServerAddr.sin_family = AF_INET; 
        int errNo = connect(clientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));  
        if(errNo == 0)  
        {   
            // 格式化data长度
            char len[10] = {0};
            sprintf(len, "%d", data.length());
            std::string strLen = len;

            //  "POST /[req] HTTP/1.1\r\n"
            //  "Connection:Keep-Alive\r\n"
            //  "Accept-Encoding:gzip, deflate\r\n"
            //  "Accept-Language:zh-CN,en,*\r\n"
            //  "Content-Length:[len]\r\n"
            //  "Content-Type:application/x-www-form-urlencoded; charset=UTF-8\r\n"
            //  "User-Agent:Mozilla/5.0\r\n\r\n"
            //  "[data]\r\n\r\n";
            std::string strSend = " HTTP/1.1\r\n"
                "Cookie:16888\r\n"
                "Content-Type:application/x-www-form-urlencoded\r\n"
                "Charset:utf-8\r\n"
                "Content-Length:";
            strSend = "POST " + req + strSend + strLen + "\r\n\r\n" + data;

            // 发送
            errNo = send(clientSocket, strSend.c_str(), strSend.length(), 0);
            if(errNo > 0)  
            {  
                //cout<<"发送成功\n";
            }
            else
            {
                std::cout << "errNo:" << errNo << std::endl; 
                return ret;
            }

            // 接收
            char bufRecv[3069] = {0};
            errNo = recv(clientSocket, bufRecv, 3069, 0);
            if(errNo > 0)  
            {  
                ret = bufRecv;// 如果接收成功,则返回接收的数据内容
            }
            else
            {
                std::cout << "errNo:" << errNo << std::endl; 
                return ret;
            }
        }  
        else  
        {  
            errNo = WSAGetLastError();  
        }  
        // socket环境清理
        ::WSACleanup();  
    }
    catch (...)
    {
        return "";
    }
    return ret;
}

// 合成JSON字符串
std::string HttpRequest::genJsonString(std::string key, int value)
{
    char buf[128] = {0};
    sprintf(buf, "{\"%s\":%d}", key.c_str(), value);
    std::string ret = buf;
    return ret;
}

// 分割字符串
std::vector<std::string> HttpRequest::split(const std::string &s, const std::string &seperator)
{
    std::vector<std::string> result;
    typedef std::string::size_type string_size;
    string_size i = 0;

    while(i != s.size()){
        // 找到字符串中首个不等于分隔符的字母
        int flag = 0;
        while(i != s.size() && flag == 0){
            flag = 1;
            for(string_size x = 0; x < seperator.size(); ++x)
                if(s[i] == seperator[x]){
                    ++i;
                    flag = 0;
                    break;
                }
        }

        // 找到又一个分隔符,将两个分隔符之间的字符串取出
        flag = 0;
        string_size j = i;
        while(j != s.size() && flag == 0){
            for(string_size x = 0; x < seperator.size(); ++x)
                if(s[j] == seperator[x]){
                    flag = 1;
                    break;
                }
                if(flag == 0) 
                    ++j;
        }
        if(i != j){
            result.push_back(s.substr(i, j-i));
            i = j;
        }
    }
    return result;
}

// 从Response中查找key对应的Header的内容
std::string HttpRequest::getHeader(std::string respose, std::string key)
{
    std::vector<std::string> lines = split(respose, "\r\n");
    for (int i = 0; i < lines.size(); i++)
    {
        std::vector<std::string> line = split(lines[i], ": ");// 注意空格
        if (line.size() >= 2 && line[0] == key)
        {
            return line[1];
        }
    }
    return "";
}

使用方法

写了一个简单的控制台程序,用于测试:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// test4HTTP.cpp : 定义控制台应用程序的入口点。
//

#include "HttpRequest.h"
#include <iostream>
#include <Windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
    HttpRequest httpReq("192.168.10.100", 8888);

    std::string res = httpReq.HttpGet("/getsomething/");
    std::cout << res << std::endl; 
    Sleep(1000);

    res = httpReq.HttpPost("/postsomething/", HttpRequest::genJsonString("something", 100));
    std::cout << res << std::endl; 
    return 0;
}

几点说明

  • 发送的字符串中,“GET”和“POST”一定要用大写字母,否则会出现出现HTTP 400 错误;
  • POST请求如果有内容(std::string data不为空),“Content-Length”一定要有;
  • 亲测可用;