既然http2和http3都已经发布了,那么为什么还要学习http1.1呢?因为,首先还有很大一部分的网站依旧在使用http1.1。其次http2和http3都支持http1.1的所有核心功能,它们只是在原本的http1.1语义层之下采用了更高效的传输机制,因此理解http1.1对于理解http2和http3是有很大帮助的。
1. 请求报文
请求报文由4个部分组成,它们分别是请求行、请求头部、空行和报文主体;请求行、请求头部和空行是必需的而报文主体是可选的。
图1 http1.1的请求报文格式
一个实际的http1.1请求报文如图2所示,该报文中第1行是请求行、第2至15行是请求头部、第16行是空行,剩余的是报文主体。
图2 一个实际的http1.1请求报文
1.1 请求行
请求行又包含3个部分:请求方法、URL和协议版本;它们之间用空格分开,请求行最后以一个回车符和一个换行符结尾。回车符是"\r",换行符是"\n";后面不再重复说明。
请求方法表明想对目标资源进行何种操作,http1.1定义了下表中列出的8种请求方法,其中最常用的是GET和POST。
URL字段用来指明目标资源的位置,它只包含一个完整URL中的文件路径和查询字符串这两部分,比如"/index.php?id=24",而不包含协议、主机名和端口号。如果同一服务器上部署了多个网站,那么为了准确判断出请求的是哪个资源需要将URL字段和Host请求头的值(指定要访问的网站名)相结合使用。
协议版本字段说明该请求报文属于哪一版的http协议,比如HTTP/1.1或HTTP/1.0。
1.2 请求头部
请求头部用来告知服务器该请求和客户端本身的一些额外信息,每个请求头都是一个键值对,键和值之间用英文冒号隔开。每个请求头单独形成一行,它们的末尾都是一个回车符和换行符。
在所有的请求头中,只有Host是必需的,其它请求头都是可选的。这里,我们将一些常见的请求头列于下表中:
1.3 空行
在请求头部的后面是一个空行,它只包含一个回车符和一个换行符,不包含其它任何内容,连空格也不能包含。这个空行用于标记请求头部已结束;它是必须要有的,即便使用GET这样不包含报文主体的请求方法时也要有这个空行。
1.4 报文主体
请求报文中的报文主体就是要提交给服务器的数据,比如当我们使用POST方法提交表单时,表单中的内容就包含在请求报文的报文主体中。在某些情况下请求报文中是没有报文主体的,比如使用GET方法,此时若要向服务器传递参数,那么参数就只能包含在URL的查询字符串(query string)中。
报文主体中的数据格式由Content-Type请求头指定,主要有两种格式,我们这里简单提一下。当Content-Type的值为application/x-www-form-urlencoded时,那么提交的数据就是以&分隔的多个键值对,每个键值对的键和值用等号连接,且数据还要经过URL编码。假设有一个让用户输入姓名、年龄和国籍的表单,那么提交的数据格式是这样的:name=Mike&age=22&country=America。
当需要上传大量的二进制数据(比如文件)的时候,应该使用multipart/form-data格式。此时Content-Type的值为"multipart/form-data; boundary=3vkqffBXJh"。其中3vkqffBXJh是自定义的分隔符,它用于分隔提交数据中的不同部分。你或浏览器可以随意指定它,不过它应该要能和其它内容相区别。
此时,提交数据的格式就像下面这样。数据中的每一部分都以--3vkqffBXJh的一行开始,它的形式是在分隔符前面添加两个连字符。紧接着的是这部分数据的消息头,消息头用于说明该部分数据的相关信息,类似于请求头。每个消息头占据单独的一行,其中Content-Disposition消息头是必需的而其它消息头是可选的。在所有消息头之后是一个空行,空行后才是该部分数据的实际内容,空行用于分隔消息头和实际数据。
Content-Disposition的值中第一部分是固定不变的form-data,表明该部分数据是表单内容。第二部分是name="fieldName"这样的形式,指明该部分数据属于表单中的哪一个字段。如果这部分数据是文件的话,那么可能还有形如filename="fileName"的第三部分,它指定该文件的初始名称。对于文件数据,可能还有一个Content-Type消息头用于指定该文件的MIME类型。
此时整个报文主体以--3vkqffBXJh--的一行结束。注意,这一行的特殊之处在于分隔符的前后均有两个连字符。multipart/form-data格式的数据中每一行都以一个回车符和换行符结尾。
2. 响应报文
响应报文也由4个部分组成,它们分别是状态行、响应头部、空行和报文主体;状态行、响应头部和空行是必需的而报文主体是可选的。
图3 http1.1响应报文的格式
一个实际的http1.1响应报文如图4所示,第1行是状态行、第2到8行是响应头部、第9行是空行,后面的是报文主体(即响应的数据),该例子中的响应数据是一个html文档。
图4 一个实际的http1.1响应报文
2.1 状态行
状态行包含3个部分:协议版本、状态码和状态短语;它们之间用空格隔开,状态行的最后是一个回车符和换行符。协议版本和请求报文中的一样,表示该响应报文所属的http版本。
状态码是服务器返回的表示响应状态的代码,状态短语是对该响应状态的一个简单描述。常见的状态码和它们对应的状态短语如下表所示:
注意:状态短语中的空格和分隔协议版本、状态码和状态短语的空格的含义是不一致的。前者是为了分隔状态短语中的单词,而后者是为了分隔状态行中的不同部分。
2.2 响应头部
响应头部和请求头部差不多,它用于传递一些附加的信息;每个响应头都是一个键值对,键和值之间用英文冒号隔开。每个响应头的后面都是一个回车符和一个换行符,即每个响应头单独形成一行。
某些头部字段既可以用于请求报文又可以用于响应报文,而有些则只能用于请求报文或者只能用于响应报文。一些常见的响应头如下表所示:
2.3 空行
在响应头部的后面是一个空行,它只包含一个回车符和一个换行符,不包含其它任何内容,即便是空格也不能有。它用于指定响应头部已结束,该空行是必不可少的,即便响应报文中没有报文主体也要有这个空行。
2.4 报文主体
响应报文中的报文主体就是服务端返回的数据,它的类型由响应头"Content-Type"说明。在某些响应报文中是没有报文主体(即响应数据)的,比如状态码为304(Not Modified)的响应报文或者某些请求错误时的响应报文。
(完)