一个封装HTTP请求的函数(C++)

2023-05-16

这里封装了HTTP请求的,支持GET与POST,并支持各种参数组合,调用方式很简单
使用DEVWEB::WebRequest(string(“http://www.luaie.com/”),ret);就可以了
如果使用POST需要填冲RequestParam参数结构,具体可以参考以下代码。

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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
namespace DEVWEB
{
     struct ACloseSkt
     {
         ACloseSkt(SOCKET h)
         {
             m_h = h;
         }
         ~ACloseSkt()
         {
             if (m_h)
                 closesocket(m_h);
             m_h = 0;
         }
         SOCKET m_h;
     };
     struct RequestParam
     {
         bool            bPost;      //是否为POST请求
         const char *     pPostData;  //为POST数据,需要自已维护内存;
         unsigned int    uiPostLen;  //为POST数据长度,主要为了兼容可以上传二进制数据,一般请求就为pPostData字符串长度
         const char *     pReferer;   //请求的引用页面,就是来源页面
         const char *     pAttachHeader; //附加自定义头
         bool            bBlock;     //true=阻塞式连接,false=异步连接,*******注意:使用异步必须设置超时时间
         unsigned int    uiTimeout;  //异步超时 单位ms
         RequestParam(){
             memset ( this ,0, sizeof (RequestParam));
             bBlock = true ; bPost = false ;
         }
     };
     void GetRealIP(string& ip, string& retip)
     {
         retip = ip;
         unsigned long t = inet_addr(( char *)( LPCSTR )ip.c_str());
         if (t == INADDR_NONE)
         {
             hostent* hostInfo = gethostbyname(( char *)( LPCSTR )ip.c_str());
             if (hostInfo)
             {
                 struct in_addr *addr;
                 addr = ( struct in_addr*)hostInfo->h_addr_list[0];
                 if (addr!=NULL)
                 {
                     retip = inet_ntoa(*addr);
                 }
             } else {
                 TRACE1( "GetRealIP can't parse domain %s\n" ,ip.c_str());
             }
         }
     }
     //
     //szURL 一个完整的URL仅HTTP,HTTPS不支持,可以包含GET参数,如index.php?username=test
     //response 为请求返回的结果,包含HTTP头信息
     //pRP为附加参数,完成更复杂的请求
     ///
     bool WebRequest( const char * szURL, std::string& response, RequestParam* pRP = 0)
     {
         if (!szURL ) return false ;
         SOCKET hSkt = socket(AF_INET,SOCK_STREAM,0);
         if (INVALID_SOCKET == hSkt){ OutputDebugString( "WebRequest socket create failed!\n" ); return false ;}
         ACloseSkt askt(hSkt);
         //是否设置为异步
         if ( pRP && pRP->bBlock == false )
         {
             ULONG nMode = 1;
             ioctlsocket( hSkt,FIONBIO,&nMode);
         }
         string strURL(szURL),host,ip,requrl;
         unsigned int nport = 80;
         if ( stricmp(string(strURL.substr(0,7)).c_str(), "http://" ) )
         {
             OutputDebugString( "WebRequest parse url error, need http://\n" );
             return false ;
         } else //parse url;
             size_t nMH = strURL.find( ':' ,8);
             size_t nPre =strURL.find( '/' ,8);
             if ( nMH == -1 && nPre == -1)
             {
                 host    = strURL.substr(7);
                 requrl  = "/" ;
             } else if ( nPre != -1){
                 if ( nMH != -1 && nPre > nMH){
                     host = strURL.substr(7,nMH-7);
                     nport = atoi ( string(strURL.substr(nMH+1, nPre-1-nMH)).c_str());
                 } else {
                     host = strURL.substr(7,nPre-7);
                 }
                 requrl = strURL.substr(nPre);
             } else if (nMH != -1){
                 host = strURL.substr(7, nMH-7);
                 nport= atoi ( string(strURL.substr(nMH+1)).c_str());
                 requrl = "/" ;
             }
         }
         GetRealIP(host,ip);
         sockaddr_in addr;
         addr.sin_addr.S_un.S_addr = inet_addr( ip.c_str() );
         addr.sin_port = htons(nport);
         addr.sin_family = AF_INET;
         if (pRP && pRP->bBlock)
         {
             if (SOCKET_ERROR == connect( hSkt, (sockaddr*)&addr, sizeof (addr)))
             {
                 OutputDebugString( "WebRequest connect server failed!\n" );
                 return false ;
             }
         } else {
             if (SOCKET_ERROR == connect( hSkt, (sockaddr*)&addr, sizeof (addr)))
             {
                 if ( WSAGetLastError() == 10035 )
                 {
                     //connectioning
                 } else {
                     OutputDebugString( "WebRequest connect server failed!\n" );
                     return false ;
                 }
             }
             DWORD dwTick = GetTickCount();
             do {
                 fd_set    Set,WSet;
                 FD_ZERO(&Set);
                 FD_ZERO(&WSet);
                 FD_SET(hSkt,&Set);
                 FD_SET(hSkt,&WSet);
                 timeval time ;
                 time .tv_sec = 0;
                 time .tv_usec = 0;
                 int nS = select(0, &Set, &WSet, NULL, & time );
                 if ( nS == SOCKET_ERROR )
                 {
                     OutputDebugString( "WebRequest connect server failed!(SELECT)\n" );
                     return false ;
                 } else if (nS){
                     break ; //connect sucess.
                 } else {
                     if ( (GetTickCount() - dwTick) > pRP->uiTimeout )
                     {
                         //timeout
                         OutputDebugString( "WebRequest connect server timeout!(SELECT)\n" );
                         return false ;
                     }
                 }
             } while ( true );
         }
         //fill header;
         string header;
         bool bSendBin = false ;
         if (pRP)
         {
             header.append( pRP->bPost ? "POST " : "GET " );
             header.append(requrl);
             header.append( " HTTP/1.1\r\n" );
             header.append( "host:" );
             header.append(host);
             header.append( "\r\nUser-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)\r\n" );
             header.append( "Content-Type:application/x-www-form-urlencoded\r\n" );
             header.append( "Accept:text/html,application/xhtml+xml,*/*\r\nConnection:close\r\n" );
             char szCSize[50];
             sprintf (szCSize, "Content-Length:%d\r\n\r\n" ,pRP->uiPostLen);
             header.append(szCSize);
             if (pRP->pPostData){
                 if ( strlen (pRP->pPostData) <= pRP->uiPostLen){
                     bSendBin = true ;
                 } else {
                     header.append(pRP->pPostData);
                 }
             }
         } else {
             header.append( "GET " );
             header.append(requrl);
             header.append( " HTTP/1.1\r\n" );
             header.append( "host:" );
             header.append(host);
             header.append( "\r\nUser-Agent:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)\r\n" );
             header.append( "Content-Type:application/x-www-form-urlencoded\r\n" );
             header.append( "Accept:text/html,application/xhtml+xml,*/*\r\nConnection:close\r\n\r\n" );
         }
         size_t headerlen = header.size();
         size_t nSendLen = 0;
         const char * pdata = header.c_str();
         DWORD dwTick = GetTickCount();
         do
         {
             int n = send(hSkt, pdata + nSendLen, int (headerlen - nSendLen),0);
             if ( n == SOCKET_ERROR ){
                 if ( 10035 == WSAGetLastError())
                 {
                     //wait for send.
                     if (pRP && GetTickCount() - dwTick >= pRP->uiTimeout)
                     {
                         OutputDebugString( "WebRequest send failed!\n" );
                         return false ;
                     }
                     Sleep(10);
                 } else {
                     OutputDebugString( "WebRequest send failed!\n" );
                     return false ;
                 }
             } else if ( n==0)
             {
                 OutputDebugString( "WebRequest send failed!\n" );
                 return false ;
                 break ;
             } else {
                 dwTick = GetTickCount();
                 nSendLen += n;
             }
         } while (nSendLen < headerlen );
         if (bSendBin && pRP && pRP->pPostData && pRP->uiPostLen)
         {
             nSendLen = 0;
             pdata = ( const char *) pRP->pPostData;
             dwTick = GetTickCount();
             do
             {
                 int n = send(hSkt, pdata + nSendLen, pRP->uiPostLen - nSendLen,0);
                 if ( n == SOCKET_ERROR ){
                     if ( 10035 == WSAGetLastError())
                     {
                         //wait for send.
                         if (pRP && GetTickCount() - dwTick >= pRP->uiTimeout)
                         {
                             OutputDebugString( "WebRequest send timeout!\n" );
                             return false ;
                         }
                         Sleep(10);
                     } else {
                         OutputDebugString( "WebRequest send failed!\n" );
                         return false ;
                     }
                 } else if ( n==0)
                 {
                     OutputDebugString( "WebRequest send failed!\n" );
                     return false ;
                     break ;
                 } else {
                     dwTick = GetTickCount();
                     nSendLen += n;
                 }
             } while (nSendLen < pRP->uiPostLen );
         }
         //recv response
         char    buf[2049];
         string& request = response;
         request.clear();
         dwTick = GetTickCount();
         do
         {
             int n = recv(hSkt, buf,2048,0);
             if ( n == SOCKET_ERROR )
             {
                 if ( 10035 != WSAGetLastError() )
                 {
                     OutputDebugString( "DevWebService recv failed!\n" );
                     return 0;
                     break ;
                 } else {
                     if (pRP && GetTickCount() - dwTick >= pRP->uiTimeout){
                         OutputDebugString( "WebRequest recv timeout!\n" );
                         return false ;
                     }
                     Sleep(10);
                 }
             } else if ( n == 0 ){
                 //host close recv finish
                 OutputDebugString( "WebRequest Recv FINISHED!\n" );
                 break ;
             } else {
                 buf[n] = '\0' ;
                 request.append(buf);    dwTick = GetTickCount();
             }
         } while ( true );
         return true ;
     }
}
//test code
     string rs;
     char post[80]; sprintf (post, "username=xj&userpassword=123456" );
     DEVWEB::RequestParam rp;
     rp.bPost = true ;
     rp.pPostData = post;
     rp.uiPostLen = strlen (post);
     if ( DEVWEB::WebRequest( "http://www.paobuke.com/wp-login.php" , rs,&rp))
     {
         AfxMessageBox( rs.c_str());
     }
 
 

近期一位朋友想写iOS上的应用,打算从微博应用做起,第一步先做一个微博客户端出来,然后做一个手机微博应用出来,具体做什么还不甚清楚,其实是在尝试中。而我正好在用asio写网络库,于是主动提出了承担web服务器网络库的部分,也是为了给我自己封装的网络库中增加一个http模块。

http大家都不陌生,每天打开网页,地址栏前大多数显示的都是http,当然还有https等等,以前跟rangerlee讨论curl的时候有说过post和get,不是很清楚,查阅了众多文章和资料,有点小懂了。

统一资源定位符(URL,英语 Uniform / Universal Resource Locator 的缩写)也被称为网页地址,是因特网上标准的资源的地址(Address)。其实URL就是代表一个特定地址的因特网标准资源URI。http请求中的get post put delete就是对这个资源进行 查 增 改 删 ,有点类似于数据库中的四大操作。get和post最主要的区别是前者是查询,后者是修改,get类似于C++中const函数,而post类似于set或者add函数。

原理:

GET

根据HTTP标准,GET用于信息的获取,并且是安全和幂等的。

安全:GET操作用于获取信息/资源,并非修改信息/资源。主要表现在不能修改信息。

幂等:这是一个数学/计算机上的概念。对于单目运算来说,如果一次运算和多次运算的结果是一样的,则该运算是幂等的,例如:C++中的abs(abs(a)) = abs(a),所以abs函数运算就是幂等的;对于双目运算,两个相等的参与运算的值在运算之后的结果仍然等于这个值,则该运算是幂等的,例如:C++中的max(a, a) = a,所以max函数的幂等的。

而GET是在同一个地址下获取到的资源是相同的,并且没有改变,所以GET是安全的、幂等的。

不过,有些特殊情况也会认为是幂等的。例如:新闻某门户网站的头条新闻,可能在不断的更新,用户可能在不同的时间看到的内容不尽相同,但是这也认为是幂等的,因为对用户来说,他们访问的资源是同一个地址的。

POST

根据HTTP标准,POST用于可能修改服务器资源的请求。并没有什么特殊规定。

例如:最常见的就是留言了,留言完之后页面会刷新,不管是整体刷新还是Ajax局部刷新,这时候用的请求就是POST

 

表现形式:

HTTP格式为:

<request line>

<headers>

<blank line>

[<request-body>]

先是一个请求行(request line),用来说明请求类型、请求地址、HTTP版本;然后是头部(headers),用来说明服务器的一些附加信息;下来是一个空行(blank line);再下来是数据主体(request-body)。

GET格式

GET / HTTP/1.1
Host: www.cppfans.org
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10 AlexaToolbar/alxg-3.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3

 

POST格式

POST /api/posts/create.json HTTP/1.1
Host: duoshuo.com
Connection: keep-alive
Content-Length: 283
Origin: http://duoshuo.com
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.10 (KHTML, like Gecko) Chrome/23.0.1262.0 Safari/537.10 AlexaToolbar/alxg-3.1
Content-Type: application/x-www-form-urlencoded
Accept: */*
Referer: http://duoshuo.com/cors/index.html?xdm_e=http%3A%2F%2Fjkirin.com&xdm_c=default693&xdm_p=1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.3

以上数据是通过Chrome的元素审查中的Network抓取到的。

1.地址的区别

举个例子:

百度搜索的地址:

http://www.baidu.com/s?tn=monline_4_dg&ie=utf-8&bs=http&f=8&rsv_bp=1&wd=http+get+post&rsv_sug3=9&rsv_sug1=7&rsv_sug4=325&inputT=2533

Get请求会把数据附在URL之后,以?分割URL和传输数据,多个参数用&连接,上述URL地址可以堪为URL是http://www.baidu.com/s,后面的tn=monline_4_dg ie=utf-8 bs=http等都是参数。

遇到空格用+替代,上述URL中的搜索词是http get post,而URL表现出来的是wd=http+get+post。

数字和字母原样不变。wd=http+get+post

中文和其他字符用Base64加密,例如有些URL表现为%D4%E3%A0%BD,其中%XX中XX表示该符号的16进制ANSII码。

POST请求:把修改的数据放置在是HTTP包的包体中进行发送。

Get请求的URL会在地址栏中显示出来,而Post只是修改,并不会改变URL。

2.传输数据的限制

HTTP协议对URL长度和传输的数据长度没有任何限制,不过在实际开发中会根据浏览器的限制条件做一些规定。

GET:根据浏览器和操作系统有一些限制。例如:IE(包含IE内核)浏览器的URL限制是2K+35个字节长度,而其他浏览器理论没有限制,但却取决于操作系统支持的长度。

POST:理论没有传输数据的限制,但总不能提交一个过大的数据,这样会很慢,所以Web服务器一般都会做限制的。

3.安全性

POST的安全性高于GET,这里是指Security而不是Safe,因为Get的URL可以通过分析得出一些数据出来,还有Cookie和历史记录等等都会造成一些恶意攻击或破解。

 

好了,关于GET和POST就说这么多了,下来就是要写一个处理这些请求的http服务器了。有人会说为什么要自己写,而不是用Apache或者nginx等已经成熟的Web服务器?因为他们太复杂了,功能繁杂,而我却不需要这么多功能,所以我写一个简单实用的http server就可以了,不过可以借鉴成熟Web服务器的主要功能代码。敬请期待吧,估计测试和投入使用会时挺长时间的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一个封装HTTP请求的函数(C++) 的相关文章

随机推荐

  • bat脚本禁用和开启本地连接

    netsh interface set interface name 61 34 本地连接 34 admin 61 disabled 禁用本地连接 netsh interface set interface name 61 34 本地连接
  • 一个PHP的QRcode类,与大家分享

    类的代码 View Code lt php eval gzinflate base64 decode 39 7X1td9s2svDn3nP2PzBZNZJiKRb1ZtmxvY 43 bOE3u2o5rp9u7N5v1oSTaZqO3UHQ
  • Java程序员的黄金5年,从入行到大牛的晋升之路

    在程序界流行着一种默认的说法叫 黄金5年 xff0c 也就是一个程序员从入职的时候算起 xff0c 前五年的选择直接影响着整个职业生涯中的职业发展方向和薪资走向 xff0c 如何走好这5年 xff0c 彻底从一个刚入行的菜鸟蜕变成可以以不变
  • Gin 框架的路由结构浅析

    Gin 是 go 语言的一款轻量级框架 xff0c 风格简单朴素 xff0c 支持中间件 xff0c 动态路由等功能 gin项目github地址 路由是web框架的核心功能 在没有读过 gin 的代码之前 xff0c 在我眼里的路由实现是这
  • 红米手机5 Plus启用root超级权限的步骤

    红米手机5 Plus怎么开启root超级权限 xff1f 做开发的人清楚 xff0c Android机器有root超级权限 xff0c 一旦手机开启root相关权限 xff0c 就可以实现更强的功能 xff0c 举个栗子做开发的人企业的营销
  • 基于vue解决大数据表格卡顿问题

    点我在线体验Demo 请用电脑查看 亲测苹果电脑 xff0c chrome浏览器无卡顿现象 xff0c 其它浏览器并未测试 xff0c 如遇到卡顿请备注系统和浏览器 xff0c 方便我后续优化 xff0c 谢谢 先看一下效果 一共1000
  • raid1损坏一块盘之后的处理方式

    在企业生产环境中 xff0c 假如raid1两块盘中的一块损坏了 xff0c 后续如何处理 xff1f 直接换下损坏的磁盘是否会对服务有影响 xff08 如何把影响降到最低 xff09 xff0c 加入新的磁盘后是否还需要重新做raid1
  • Landsat Tm5辐射定标和大气校正(转)

    一 辐射定标 1 由于ENVI 4 4 中有专门进行辐射定标的模块 xff0c 因此实际的操作十分简单 将原始TM 影像打开以后 xff0c 选择 Basic Tools Preprocessing Calibration Utilitie
  • Traversing the Dept Security tree

    We can use the connect by prior function provided by Oracle to traverse the Dept security Tree Suppose an Organization h
  • Reconfigurable computing[可重构计算]

    在实验室跟老师做一些硬件加速相关的东西 xff0c 看文献时看到Reconfigurable computing xff0c 发现这个很有意思 现在每天都有越来越多的数据产生 xff0c 要处理这些数据如果单纯用CPU计算的话会耗费很多时间
  • 嵌入式作业STM32采用串口DMA方式发送数据

    目录 前言 要求 一 DMA的基本介绍 DMA的基本定义 DMA的主要特征 STM32F411x系列芯片DMA控制器 二 通过CubeMX配置项目 1 创建项目 2 选择芯片STM32F103C8T6 3 设置RCC 4 设置串口 5 设置
  • C ~ char int 等数据转换问题

    1 xff0c char型数字转换为int型 char a 61 34 32 34 printf 34 d n 34 a 0 39 0 39 输出结果为3 2 xff0c int转化为char 1 字符串转换成数字 xff0c 用atoi
  • curl get请求添加header头信息

    function get url ch 61 curl init curl setopt ch CURLOPT HTTPGET true curl setopt ch CURLOPT RETURNTRANSFER 1 TRUE 将curl
  • 关于 RESTFUL API 安全认证方式的一些总结

    常用认证方式 在之前的文章 REST API 安全设计指南 与 使用 AngularJS amp NodeJS 实现基于 token 的认证应用 两篇文章中 xff0c 译 web权限验证方法说明 中也详细介绍 xff0c 一般基于REST
  • C++ REST SDK的基本用法

    微软开发了一个开源跨平台的http库 C 43 43 REST SDK xff08 http casablanca codeplex com xff09 xff0c 又名卡萨布兰卡Casablanca xff0c 有个电影也叫这个名字 xf
  • ubuntu下socket通信

    之前的博文介绍了如何在ubuntu下实现unix domain socket通信 xff0c 但只是本地的通信 xff0c 虽然过程和网络通信很类似 xff0c 但这里还是有必要了解下真正的socket通信 首先贴出server端的c代码
  • c语言中宏定义中void,C语言中宏定义几道问题!

    C语言中宏定义几道问题 xff01 答案 1 信息版本 xff1a 手机版 解决时间 2020 04 27 20 44 已解决 2020 04 27 17 15 一 执行下列程序 define MA x y x y k 61 5 k 61
  • IE浏览器自动配置脚本的使用(代理上网)

    以前在FireFox中设置过代理服务器自动配置脚本 xff0c 对于访问某些无法访问的网站非常有效 xff0c 在IE中应该也是有效的 xff0c 但是我配置了好几次都没有配置成功 xff0c 今天发现原来是格式错误 xff0c 修改了一下
  • c语言中通过指针将数值赋值到制定内存地址

    1 一种直观的方法 假设现在需要往内存0x12ff7c地址上存入一个整型数0x100 我们怎么才能做到呢 xff1f 我们知道可以通过一个指针 向其指向的内存地址写入 数据 xff0c 那么这里的内存地址0x12ff7c其本质不就是一个指针
  • 一个封装HTTP请求的函数(C++)

    这里封装 了HTTP请求的 xff0c 支持GET与POST xff0c 并支持各种参数组合 xff0c 调用方式很简单 使用DEVWEB WebRequest string http www luaie com ret 就可以了 如果使用