HTTP编程—完结

4.4.4客户端和服务器端交互

HTTP1.0定义了3种请求方法:GET、POST、HEAD;HTTP1.1新增5种请求方法:PUT、DELETE、CONNECT、OPTIONS、TRACE。

GET:请求指定的页面信息,并返回实体主体。

POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。

HEAD:类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。

PUT:从客户端向服务器传送的数据取代指定的文档的内容。

DELETE:请求服务器删除指定的页面。

CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

OPTIONS:允许客户端查看服务器的性能。

TRACE:回显服务器收到的请求,主要用于测试或诊断。

HTTP响应(Reponce)的状态码:

1xx:指示信息--表示请求已接收,继续处理。

2xx:成功—表示请求已被成功接收、理解、接受。

3xx:重定向—要完成请求必须进行更进一步的操作。

4xx:客户端错误—请求有语法错误或请求无法实现。

5xx:服务器端错误—服务器未能实现合法的请求。

常见状态码:

200 OK //客户端请求成功

400 Bad Request //客户端请求有语法错误,不能被服务器所理解

401 Unauthorized  //请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用

403 Forbidden   //服务器收到请求,但是拒绝提供服务

404 Not Found      //请求资源不存在,eg:输入了错误的URL

500 Internal Server Error //服务器发生不可预期的错误

503 Server Unavailable //服务器当前不能处理客户端的请求,一段时间后可能恢复正常

使用WireShark或fiddler抓HTTP协议包,如下所示:

 

上图红色部分是HTTP客户端请求(GET),蓝色部分是HTTP服务器端响应(200 ok表示请求成功)。

常用的请求有GET和POST,区别如下:

GET请求:

GET /books/?name=Professional%20Ajax HTTP/1.1
Host: www.wrox.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
Gecko/20050225 Firefox/1.0.1
Connection: Keep-Alive
POST请求:
POST / HTTP/1.1 //请求行

Host: www.wrox.com //2-7行是请求头部

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)

Gecko/20050225 Firefox/1.0.1

Content-Type: application/x-www-form-urlencoded

Content-Length: 40

Connection: Keep-Alive
(----此处空一行----) //空行

name=Professional%20Ajax&publisher=Wiley //请求数据,即HTTP消息主体

这是我从网上找的2个例子。当我们发送一些数据请求时,如用户名、密码,GET请求是放入URL中发送的;而且GET请求是可被缓存的,参数保留在浏览器历史中。因此会被爬虫爬走一些关键性的数据。

若使用POST请求,数据是存放在HTTP消息主体中发送的;且POST请求不会被缓存,参数不会保存在浏览器中。因此使用POST请求更加安全。

参考博客:https://www.cnblogs.com/ranyonsue/p/5984001.html

4.4.5 CURL编程

在win10平台下,使用vs2017编译CURL。

(1)在https://curl.haxx.se/download.html下载源码。

(2)解压后,放入D盘,进入D:\curl-7.62.0\winbuild,并复制其文件夹路径。

(3)打开开始菜单,找到vs2017,若编译64位,则选择”适用于VS 2017的x64本机工具命令提示”;若编译32位,则选择”适用于VS 2017的x86本机工具命令提示”。在这里,我们选择编译64位。

(4)进入命令行后,输入cd D:\curl-7.62.0\winbuild,进入winbuild目录;然后输入命令nmake /f Makefile.vc mode=static VC=15 MACHINE=x64 ENABLE_IDN=no DEBUG=no,等待即可。注:这里一定要加上ENABLE_IDN=no,不然它会按照ENABLE_IDN=yes来编译,代码运行后会出现”无法解析的外部符号 __imp__IdnToAscii@20,该符号在函数 _curl_win32_idn_to_ascii 中被引用”和”无法解析的外部符号 __imp__IdnToUnicode@20,该符号在函数 _curl_win32_ascii_to_idn 中被引用”这样的错误。

(5)若使用动态编译,则将”mode=static”改为”mode=dll”;若使用x86平台,将“MACHINE=x64”改为“MACHINE=x86”;  若需要debug版,将“DEBUG=no”改为“DEBUG=yes”;若使用其它版本的Visual Studio,则”VC”后的数字需要改为对应Visual Studio的版本。

(6)编译完成后,打开curl-7.62.0\builds文件夹,libcurl-vc15-x64-release-static-ipv6-sspi-winssl存放的就是编译结果(名称最短的那个文件夹)。我们可以将编译完成的文件夹放入其他路径,以便长期使用,如下图所示。

编译完成CURL,该如何使用呢?

(1)在vs2017中,新建一个项目。右击:项目->属性;将配置改为”所有配置”,即包括Debug调试版本和Release发行版本;平台选择”x64”。

(2)选择VC++目录,在包含目录处,添加”C:\CURL_WIN_X64\include”;在库目录处,添加”C:\CURL_WIN_X64\lib”。因为我们将编译好的头文件、库文件放在C盘CURL_WIN_X64目录下。

(3)选择目录:编译器->输入,在附加依赖项处,添加”libcurl_a.lib”、”ws2_32.lib”、”Crypt32.lib”、”wldap32.lib”,如下图所示。

(4)若使用静态编译的CURL版本,则需要加入预处理定义:CURL_STATICLIB。在C/C++->预处理器->预处理器定义,添加CURL_STATICLIB。

(5)若使用的是Release版本,则进入目录:C/C++->代码生成,在运行库处,选择MD。官方不建议使用MT和MTd,即静态链接多线程库,加d表示是Debug版本。

(6)在解决方案那里,解决方案配置选择Release或Debug,解决方案平台选择x64。

//http发送GET请求

#include <curl/curl.h>    

 

static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)

{

size_t written = fwrite(ptr, size, nmemb, (FILE *)stream);

return written;

}

 

void curl_get_req(const char * url,const char * filename)

{

CURL *curl_handle;

FILE *pagefile;

//static const char *pagefilename = "page.out";

 

if (url==NULL || filename==NULL)

{

return;

}

 

curl_global_init(CURL_GLOBAL_ALL);

 

/* init the curl session */

curl_handle = curl_easy_init();

 

/* set URL to get here */

curl_easy_setopt(curl_handle, CURLOPT_URL,url);

 

/* Switch on full protocol/debug output while testing */

curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);

 

/* disable progress meter, set to 0L to enable and disable debug output */

curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);

 

/* send all data to this function  */

curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);

 

/* open the file */

//pagefile = fopen(pagefilename, "wb");

errno_t err = fopen_s(&pagefile,filename,"wb");

if (err==0) {

//if (pagefile) {

/* write the page body to this file handle */

curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);

 

/* get it! */

curl_easy_perform(curl_handle);

 

/* close the header file */

fclose(pagefile);

}

 

/* cleanup curl stuff */

curl_easy_cleanup(curl_handle);

 

curl_global_cleanup();

}

 

int main(int argc, char ** argv)

{

static const char * load_png = "baidu.PNG";

const char * url = "https://www.baidu.com/img/bd_logo1.png?where=super";

curl_get_req(url, load_png);

 

return 0;

}

运行结果:

*   Trying 112.80.248.75...

* TCP_NODELAY set

* Connected to www.baidu.com (112.80.248.75) port 443 (#0)

* schannel: SSL/TLS connection with www.baidu.com port 443 (step 1/3)

* schannel: checking server certificate revocation

* schannel: sending initial handshake data: sending 178 bytes...

* schannel: sent initial handshake data: sent 178 bytes

* schannel: SSL/TLS connection with www.baidu.com port 443 (step 2/3)

* schannel: failed to receive handshake, need more data

* schannel: SSL/TLS connection with www.baidu.com port 443 (step 2/3)

* schannel: encrypted data got 3559

* schannel: encrypted data buffer: offset 3559 length 4096

* schannel: SSL/TLS connection with www.baidu.com port 443 (step 2/3)

* schannel: encrypted data got 347

* schannel: encrypted data buffer: offset 347 length 4096

* schannel: sending next handshake data: sending 126 bytes...

* schannel: SSL/TLS connection with www.baidu.com port 443 (step 2/3)

* schannel: encrypted data got 226

* schannel: encrypted data buffer: offset 226 length 4096

* schannel: SSL/TLS handshake complete

* schannel: SSL/TLS connection with www.baidu.com port 443 (step 3/3)

* schannel: stored credential handle in session cache

> GET /img/bd_logo1.png?where=super HTTP/1.1

Host: www.baidu.com

Accept: */*

 

* schannel: client wants to read 16384 bytes

* schannel: encdata_buffer resized 17408

* schannel: encrypted data buffer: offset 0 length 17408

* schannel: encrypted data got 7074

* schannel: encrypted data buffer: offset 7074 length 17408

* schannel: decrypted data length: 4000

* schannel: decrypted data added: 4000

* schannel: decrypted data cached: offset 4000 length 16384

* schannel: encrypted data length: 3045

* schannel: encrypted data cached: offset 3045 length 17408

* schannel: decrypted data length: 96

* schannel: decrypted data added: 96

* schannel: decrypted data cached: offset 4096 length 16384

* schannel: encrypted data length: 2920

* schannel: encrypted data cached: offset 2920 length 17408

* schannel: failed to decrypt data, need more data

* schannel: schannel_recv cleanup

* schannel: decrypted data returned 4096

* schannel: decrypted data buffer: offset 0 length 16384

< HTTP/1.1 200 OK

< Accept-Ranges: bytes

< Cache-Control: max-age=315360000

< Connection: Keep-Alive

< Content-Length: 7877

< Content-Type: image/png

< Date: Mon, 12 Nov 2018 13:53:40 GMT

< Etag: "1ec5-502264e2ae4c0"

< Expires: Thu, 09 Nov 2028 13:53:40 GMT

< Last-Modified: Wed, 03 Sep 2014 10:00:27 GMT

< P3p: CP=" OTI DSP COR IVA OUR IND COM "

< Server: Apache

< Set-Cookie: BAIDUID=DA921C00BF8A31532A27D2D6BFB1F355:FG=1; expires=Tue, 12-Nov-19 13:53:40 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

<

* schannel: client wants to read 4287 bytes

* schannel: encrypted data buffer: offset 2920 length 17408

* schannel: encrypted data got 1425

* schannel: encrypted data buffer: offset 4345 length 17408

* schannel: decrypted data length: 4000

* schannel: decrypted data added: 4000

* schannel: decrypted data cached: offset 4000 length 16384

* schannel: encrypted data length: 316

* schannel: encrypted data cached: offset 316 length 17408

* schannel: decrypted data length: 287

* schannel: decrypted data added: 287

* schannel: decrypted data cached: offset 4287 length 16384

* schannel: encrypted data buffer: offset 0 length 17408

* schannel: decrypted data buffer: offset 4287 length 16384

* schannel: schannel_recv cleanup

* schannel: decrypted data returned 4287

* schannel: decrypted data buffer: offset 0 length 16384

* Connection #0 to host www.baidu.com left intact

图片如下所示:

POST请求中,有四种常见的提交数据方式:application/x-www-form-urlencoded、multipart/form-data、application/json、text/xml。将application/json作为请求头,用来告诉服务器消息主体是序列化后的JSON字符串。大家可以自己用JSON方式来实现POST请求。

猜你喜欢

转载自blog.csdn.net/Bing_bing_bing_/article/details/84000198
今日推荐