①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。不过,当前的大多数浏览器只支持GET和POST,Spring 3.0提供了一个HiddenHttpMethodFilter,允许你通过“_method”的表单参数指定这些特殊的HTTP方法(实际上还是通过POST提交表单)。服务端配置了HiddenHttpMethodFilter后,Spring会根据_method参数指定的值模拟出相应的HTTP方法,这样,就可以使用这些HTTP方法对处理方法进行映射了。
②为请求对应的URL地址,它和报文头的Host属性组成完整的请求URL。
③是协议名称及版本号。
④是HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。
⑤是报文体,它将一个页面表单中的组件值通过param1=value1&m2=value2的键值对形式编码成一个格式化串,它承载多个请求参数的数据。不但报文体可以传递请求参数,请求URL也可以通过类似于“/chapter15/user.html? param1=value1&m2=value2”的方式传递请求参数。
对照上面的请求报文,我们把它进一步分解,你可以看到一幅更详细的结构图:
常见的HTTP请求报文头属性
Accept -请求报文通过一个Accept报文属性告诉服务器,客户端接收什么类型的响应;Accept属性的值可以为一个或多个MIME类型的值,MIME格式:大类型/小类型[;参数]
Accept:text/plain
比如:
text/html,html文件
text/css,css文件
text/javascript,js文件
image/*,所有图片文件
Cookie --客户端的cookie就是通过这个报文头属性传给服务器端
Cookie: $Version=1; Skin=new;jsessionid=5F4771183629C9834F8382E23BE13C4C
服务端是怎么知道客户端的多个请求是隶属于一个Session呢?注意到后台的那个jsessionid=5F4771183629C9834F8382E23BE13C4C木有?原来就是通过HTTP请求报文头的Cookie属性的jsessionid的值关联起来的!(当然也可以通过重写URL的方式将会话ID附带在每个URL的后面哦)。
Referer:表示这个请求是从哪个URL过来的,假如你通过google搜索出一个商家的广告页面,你对这个广告页面感兴趣,鼠标一点发送一个请求报文到商家的网站,这个请求报文的Referer报文头属性值就是http://www.google.com。
Cache-Control
对缓存进行控制,如一个请求希望响应返回的内容在客户端要被缓存一年,或不希望被缓存就可以通过这个报文头达到目的。
如以下设置,相当于让服务端将对应请求返回的响应内容不要在客户端缓存:
Cache-Control: no-cache
User-Agent:浏览器通知服务器,客户端浏览器与操作系统相关信息
ser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) uChrome/69.0.3497.100 Safari/537.36
Connection:表示客户端与服务连接类型;Keep-Alive表示持久连接,close已关闭
Connection: keep-alive
Content-Length:请求体的长度
POST http://39.108.107.149:8080/vk/app/rest/ddp/iModelServiceImpl/findModelByType HTTP/1.1
User-Agent: Fiddler
Host: 39.108.107.149:8080
Content-Length: 11
Host:请求的服务器主机名
Content-Type:请求的与实体对应的MIME信息。如果是post请求,会有这个头,默认值为application/x-www-form-urlencoded,表示请求体内容使用url编码
Content-Type: application/x-www-form-urlencoded
Accept-Encoding:浏览器通知服务器,浏览器支持的数据压缩格式。如GZIP压缩
Accept-Encoding: gzip, deflate
Accept-Language:浏览器通知服务器,浏览器支持的语言。各国语言(国际化i18n)
Accept-Language: zh-CN,zh;q=0.9
HTTP的响应报文也由三部分组成( 响应行+响应头+响应体 ):
①报文协议及版本;
②状态码及状态描述;
③响应报文头,也是由多个属性组成;
④响应报文体,即我们真正要的“干货”。
响应状态码–和请求报文相比,响应报文多了一个’响应状态码’,它以’清晰明确’的语言告诉客户端本次请求的处理结果:
1xx 消息,一般是告诉客户端,请求已经收到了,正在处理,别急…
2xx 处理成功,一般表示:请求收悉、我明白你要的、请求已受理、已经处理完成等信息.
3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。
4xx 处理发生错误,责任在客户端,如客户端的请求一个不存在的资源,客户端未被授权,禁止访问等。
5xx 处理发生错误,责任在服务端,如服务端抛出异常,路由出错,HTTP版本不支持等。
获取城市天气信息,打印并保存本地txt文件
#include
#include
#include
#include
DWORD g_dwErr;//用于取得错误信息
const int MAX_SIZE = 40960;//保存数组的大小
int MainWindow::dealHttp()
{
/* 初始化 */
WSADATA wsdata;
WSAStartup(MAKEWORD(2, 2), &wsdata);
const char* hostname = "www.weather.com.cn";
struct hostent* host = gethostbyname(hostname);
/* 初始化一个连接服务器的结构体 */
sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(80);
/* 此处也可以不用这么做,不需要用gethostbyname,把网址ping一下,得出IP也是可以的 */
serveraddr.sin_addr.S_un.S_addr = *((int*)*host->h_addr_list);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
cout << "socket error" << endl;
return -1;
}
cout << "socket succeed" << endl;
if (::connect(sock, (struct sockaddr*)&serveraddr, sizeof(sockaddr_in)) == -1)
{
g_dwErr = GetLastError();
cout << "connect error" << endl;
closesocket(sock);
return -1;
}
cout << "connect succeed" << endl;
/* GET请求 */
const char* bufSned = "GET http://www.weather.com.cn/data/sk/101190101.html\r\n";
/* 发送GET请求 */
if (send(sock, bufSned, strlen(bufSned), 0) > 0)
{
cout << "send succeed" << endl;
} else
{
g_dwErr = GetLastError();
cout << "send error, 错误编号: "<< g_dwErr << endl;
closesocket(sock);
return -1;
}
/* 文件,用于把HTML源码保存起来,没什么用处,只是为了自己看一下源码而已 */
FILE *fp;
fp = fopen("get.txt","w");
char BufRecv[MAX_SIZE] = {};
int nLen = 0;
string HtmlData;
/* 开始接收数据 */
while ((nLen = recv(sock, BufRecv, MAX_SIZE, 0)) > 0)
{
/* 写文件 */
fwrite(BufRecv, 1, nLen, fp);
/* 把数组拼接成string类型,方便下面的处理 */
HtmlData += BufRecv;
}
printf("BufRecv=%s\n",BufRecv);
fclose(fp);
closesocket(sock);
return 0;
}