1.2 理解HTTP
HTTP耳熟能详,很容易和互联网、Web概念相混淆,看上去很简单的协议,其实很多技术人员并没有理解该协议的本质,本节简单介绍其相关概念,从整体上理解其本质。
1.2.1 HTTP的定义
HTTP提供了一组规则和标准,从而让信息能够在互联网上进行传播,也正是通过HTTP,互联网上的设备才能够互相通信,并明白对方的含义。
HTTP目前的版本是HTTP/1.1,定义在RFC 2616规范上,相比HTTP/0.9和HTTP/1.0版本,HTTP/1.1并没有太多的演变,只是从性能和标准化的维度做了些优化。互联网发展到目前,用户数、终端类型、终端数量、共享信息越来越多,信息表现形式也越来越丰富,基于HTTP/1.1的Web应用已经不能很好地满足需求,下一代的HTTP标准是HTTP/2.0,后续章节会讲解。
而客户端和服务器要做的就是遵循RFC 2616规范,只要正确实现该规范,很容易实现一个客户端(浏览器)和服务器,也正因为有了浏览器和服务器,HTTP应用才能够被广泛使用。
HTTP的模型很简单,是一个B/S模型,由客户端和服务器组成,交互流程很简单。
◎一个HTTP客户端发送请求至HTTP服务器,然后等待服务器的响应。
◎一个HTTP服务器负责监听端口(默认是80),然后等待客户端的请求,处理完成后,回复给客户端。
大家最熟悉的客户端就是浏览器,比如Chrome和Firefox,另外一种客户端可以称为命令行工具,比如Linux上的Curl工具。服务器软件就更多了,比较流行的就是Nginx和Apache,服务器实现HTTP并不困难,困难的是如何高效地处理客户端请求。
对于服务器开发者来说,提供HTTP服务非常简单,具体如下。
◎一个域名,这个域名定义了服务器的地址,有了域名,客户端就能够找到服务器。
◎一台主机,主机绑定域名且用来安装服务器软件,开发者不用自己实现服务器,只要安装服务器软件并启动服务即可,服务绑定80端口,端口的概念本章后续部分会描述。
◎开发者使用各种语言(比如Python、PHP)编写HTML页面,提供HTTP应用层服务。
1.2.2 HTTP语义
HTTP消息主要包括两部分,分别是HTTP语义和HTML实体,这里主要讲解HTTP语义信息,了解HTTP语义重点是理解HTTP头部(HTTP Header)。
下面通过例子解释HTTP消息的含义,当用户在浏览器上触发一个动作时,比如访问某个URL,浏览器根据用户的行为和终端环境构建消息结构体,连接上服务器,将消息体发送给服务器,然后等待响应,请求消息结构如下:
POST /index.html HTTP/1.1 Host:www.example.com Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN, zh; q=0.8, en; q=0.6 Cache-Control:no-cache Connection:keep-alive param1=b¶m2=c
接下来,服务器处理请求并发送HTTP响应。
HTTP/1.1200 OK Server: nginx/1.4.6 (Ubuntu) Date: Tue, 11 Jul 2017 07:20:22 GMT Content-Type: text/html Transfer-Encoding: chunked Content-Encoding:gzip Connection: keep-alive X-Powered-By: PHP/5.5.9-1ubuntu4.19 <! doctype html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> </head> <body> </body> </html>
通过请求/响应消息可以看出,HTTP消息由三部分组成。
◎请求行或响应行。
◎HTTP头部。
◎HTML实体,包括请求实体和响应实体。
前面两部分是HTTP的语义信息,客户端和服务器使用语义信息进行交谈,最后一部分就是HTML实体,由浏览器进行处理,对用户更有意义。
HTTP请求结构如图1-1所示,HTTP响应结构如图1-2所示。
图1-1 HTTP请求结构
图1-2 HTTP响应结构
接下来介绍HTTP语义信息。
1)HTTP头部
HTTP头部协助客户端和服务器进行“交谈”,了解双方想表达的意思,简单讲解示例中部分HTTP头部的含义。
(1)Accept-Encoding:gzip
表示浏览器支持的数据压缩算法是gzip,它等于告之服务器,是否可以使用gzip算法压缩响应后再发送。服务器收到请求后解析Accept-Encoding头部,了解客户端希望使用gzip压缩算法压缩HTTP响应。如果服务器支持gzip压缩算法,会对所有的HTML响应压缩后再发送给客户端(头部并不压缩),为了让客户端知道响应是经过gzip压缩的,需要输出Content-Encoding:gzip头部,如果服务器不支持gzip算法,也可以原样将HTML响应发送给客户端,并且不输出Content-Encoding头部。
(2)Host:www.example.com
该头部只对客户端有用,表示客户端连接互联网上的某个服务器,客户端在连接之前需要先通过DNS协议解析出www.example.com的IP地址,然后连接服务器并发送请求。
在HTTP中,有很多HTTP头部,某些头部只适用于客户端或服务器,某些头部同时适用于客户端和服务器。RFC协议要求客户端和服务器正确地理解头部,但是在现实世界中,很多客户端和终端设备没有严格地遵守HTTP。
对于开发者来说,没有必要了解每个HTTP头部的含义,但是基本的HTTP头部必须仔细领悟,可以这样说,理解HTTP其实就是理解HTTP头部。
2)请求行
GET /index.html HTTP/1.1
请求行由方法、URL、HTTP版本组成。方法表示客户端以何种方式请求服务器上的资源,比如GET方法表示获取资源,POST方法表示更新服务器资源;URL表示互联网资源的地址;HTTP/1.1表示客户端本次请求所遵循的HTTP版本,服务器也要按照同样版本的HTTP处理语义信息;本例表示请求服务器/index.html资源。
3)响应行
HTTP/1.1200 OK
响应行由HTTP版本、状态码、信息提示符组成。在本例中,HTTP/1.1表示本次响应支持HTTP/1.1;200表示本次请求被正确处理了,如果是404表示服务器上不存在客户端需要的资源;信息提示符和状态码是一一对应的,不同的状态码有不同的描述信息。
对于开发者来说,更关注HTML输出。对于用户来说,更关心HTTP消息中的HTML实体,浏览器对HTML实体进行解析,解析出来的内容才是用户关心的,客户端和服务器软件更关注HTTP头部,通过头部进行交谈。
1.2.3 HTTP的特点
HTTP本质上很简单,对于用户来说,有浏览器就可以快速获取信息,无须理解HTTP;对于开发者来说,就算不了解HTTP,也能开发一个Web应用,也正因为如此,基于HTTP的Web应用才如此流行。
对于开发者来说,可以不阅读HTTP的RFC文档,但必须掌握HTTP的几个特点,这样才能更好地开发。
1)客户端/服务器模型
HTTP是一个客户端/服务器模型,客户端和服务器通过网络交换信息。当然HTTP本身是不能传输的,需要通过网络层中的其他协议进行通信,一般构建在TCP之上。TCP能够提供一个可靠的、面向连接的传输服务,换句话说,客户端和服务器是否正确传输依赖于TCP这个协议。
2)HTTP是无状态的
HTTP是基于TCP的,当一个TCP连接关闭后,所有的HTTP请求/响应信息将全部消失。
在HTTP中,客户端通过Socket技术创建一个TCP/IP连接,并连接到服务器,完成信息交换后,就会关闭TCP连接,这种模型简单明了。所谓的无状态就是每次请求完成后,不会在客户端和服务器上保存任何的信息,对于客户端和服务器来说,根本不知道上一次请求的信息是什么,甚至不知道本次连接的对端是不是上次连接的那一端,它的生命周期随着TCP/IP连接的关闭结束了。
在互联网早期,可以说这种模型设计得很巧妙,但是现在的Web应用越来越丰富,无状态的设计已经不能适应新的情况,为了保持状态,出现了Cookie和Session技术,但是Cookie技术设计得非常不严谨,引发了很多安全问题。
介绍下Cookie是如何进行会话保持的,客户端第一次请求完成后,服务器会发送Cookie信息到客户端的计算机上,客户端下次请求的时候会携带该Cookie信息,这样服务器就知道该用户就是上一次请求的用户了。
3)HTTP是跨平台的
通过上面的讲解,读者知道HTTP就是具备一定规则的纯文本信息,任何开发语言都可以实现HTTP或者基于HTTP进行开发,开发出来的软件也很容易移植,受系统环境的影响非常少。
4)HTTP用途很广泛
Web主要使用HTTP进行传输数据,HTTP更多的是一个数据载体,对于Web应用来说更重要的是浏览器如何处理这些数据,这些本身和HTTP关系并不大。
考虑到HTTP如此简单,基于HTTP的应用非常多,比如,不管是iOS还是Andriod应用,都需要调用基于HTTP的API接口。