基础 - 请求报文结构介绍

  • 作者:KK

  • 发表日期:2017.9.7


POST请求体样本

建议你先通过《Fiddler - 基础抓包》学会如何抓取一个HTTP请求的信息

一个常见的HTTPGET请求的内容如下:

POST http://www.kkh86.com/http-test.do HTTP/1.1
Host: www.kkh86.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 15
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3368.400 QQBrowser/9.6.11974.400
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: auto-login=1

name=Jay&age=33

第一部分:请求行

第一行GET http://www.kkh86.com/http-test.do HTTP/1.1就叫做请求行,这行内容又分为以下三个元素

  1. 请求方法

    前面第一个词表示了本次HTTP请求的方法(GET、POST、PUT、DELETE、HEAD、OPTIONS、TRACE、CONNECT)


  2. 请求地址

    这个请求地址是带有host的,就算HTML里只写了“href="/http-test.do"”,但浏览器会自动跟当前网页的域名拼接成完整的地址构成这个HTTP请求信息,比如“http://www.kkh86.com/http-test.do”

    在非浏览器的请求场景中,比如通过PHP的curl函数发起请求,又或是Java、C#等代码,都必须写入完整网址,不然你只写相对路径的话人家怎么知道往哪个host发送请求呢


  3. 协议版本

    HTTP1.1表示本次通讯数据格式的书写排版是遵循HTTP的1.1版本协议的,HTTP最初的版本是1.0,但没多久就升级为1.1了,至少目前我还没见过哪个软件还使用1.0版本协议来通讯

    我虽然看地几次1.1和1.0的具体区别,但其实多年来发现知道这些区别对我们日常开发来说没任何作用,而最后我也背不出来,建议你不要去关心这些版本区别吧,因为我可以说的就是当今能在我们各种系统中使用的浏览器都使用1.1版本与服务器通讯,你学了1.0的东西也不知往哪用

    这个版本可以说是万年不变的,1.0因为某些缺陷被废弃了,1.1正在流行,无论你用什么抓包、浏览器抓包都是看到这个版本号,会看腻的

    在未来5~10年等HTTP2.0版本普及后就能在抓包过程中发现1.1和2.0两个版本号了


第二部分:请求头

下面这堆东西就是请求头,它们都是Key: value的结构,也就是只有2个元素(:号隔开),与请求行的三个元素数量都不同,很容易辨识

Host: www.kkh86.com
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 15
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3368.400 QQBrowser/9.6.11974.400
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Cookie: auto-login=1

其中Host就是请求的目标主机地址

User-Agent是请求客户端的代理头,用我的话来说就是“描述了客户端的一个字符串”

其它Connection、Accept什么的你不用太关心,看多了就熟悉它们了,通常在服务端写业务代码的时候不需要关心这些请求头,服务器的通讯层会分析并处理它们

最后那个Cookie当然就是浏览器的Cookie啦,只要Cookie还没过期,每次请求都会附在请求头里,当Cookie多了的时候就会很占带宽了,后面《注意Cookie》再专门讲这个


可以追加自定义请求头

请参考JS版代码演示《前端进阶 - 少用但偶尔会碰到 - ajax自定义header

服务端要接收这些请求头的时候,以我熟悉的PHP语言为例,可以从$_SERVER数组取到这个自定义请求头的值:$myHeader1 = $_SERVER['HTTP_MYHEAD1'];(全部自动转换成大写,前面加个HTTP前缀说明是通过HTTP协议请求发送过来的信息)


第三部分:请求体

name=Jay&age=33

请求信息底下这个就是请求体,我们可以理解为“请求的附加数据”,甚至不严格地说是请求参数,它与请求头之间会有一个空行,这点很重要

你可以发现这些内容就是UrlEncode格式,没错,GET请求把UrlEncode参数放在请求地址上,而POST请求就是把参数以UrlEncode的方式放在请求体里面,只是放的位置不同,但二者的格式是默认一致的


可以自定义请求体格式

如果在浏览器里用form标签加submit按钮提交的话,浏览器会自动将参数组装成UrlEncode格式,包括在jquery里如果这样传入一个key value对象也会自动转换成UrlEncode:

$.post('/xx.do', {
	name : 'Jay',
	age : 11
});

$.ajax({
	url : '/xx.do',
	data : {
		name : 'Jay',
		age : 11
	}
});

都会变成name=Jay&age=11放到请求体里面

要自定义格式的话只能通过ajax请求来发送:

$.ajax({
	url : '/xx.do',
	data : JSON.stringify({
		name : 'Jay',
		age : 11
	})
});

这样构造的请求报文大概如下(主要是最后一行,请求体不是UrlEncode而是JSON):

POST http://kk/xx.do HTTP/1.1
Host: kk
Connection: keep-alive
Content-Length: 23
Pragma: no-cache
Cache-Control: no-cache
Origin: http://kk
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3368.400 QQBrowser/9.6.11974.400
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: */*
Referer: http://kk/it/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8

{"name":"Jay","age":11}

每种编程语言都有默认的接收参数格式,大部分是UrlEncode格式,如果你某天调试的时候发现收不到参数,请抓包看看参数的格式是怎样的,如果是JSON或XML什么的,那就要另外换一个参数的读取方式了

比如PHP语言,是不能直接通过$_POST['name']这样来取值的,在《PHP进阶 - curl - 发送GET/POST请求》里我讲解了发送JSON数据的时候如何接收


GET方法不会有请求体

GET的请求报文是这样的:

GET http://www.kkh86.com/it/demo/js/check-all.html HTTP/1.1
Host: www.kkh86.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.104 Safari/537.36 Core/1.53.3368.400 QQBrowser/9.6.11974.400
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8

第一行是请求行,下面全是请求头,然后就没有然后了,你多看几个抓包记录就熟悉了