HTTP 协议是一个“灵活可扩展”的传输协议。HTTP 协议最初诞生的时候就比较简单,本着开放的精神只规定了报文的基本格式,比如:
报文里的各个组成部分都没有做严格的语法语义限制,可以由开发者任意定制。在发展过程中,HTTP 协议逐渐增加了请求方法、版本号、状态码、头字段等特性。而 body 也不再限于文本形式的 TXT 或 HTML,而是能够传输图片、音频视频等任意数据。
HTTP 协议是一个“可靠”的传输协议。因为 HTTP 协议是基于 TCP/IP
的,而 TCP 本身是一个“可靠”的传输协议,能够在请求方和应答方之间“可靠”地传输数据。它的具体做法与 TCP/UDP
差不多,都是对实际传输的数据(entity)做了一层包装,加上一个头,然后调用 Socket API,通过 TCP/IP
协议栈发送或者接收。
正确理解“可靠”的含义,HTTP 并不能 100% 保证数据一定能够发送到另一端,在网络繁忙、连接质量差等恶劣的环境下,也有可能收发失败。“可靠”只是向使用者提供了一个“承诺”,会在下层用多种手段“尽量”保证数据的完整送达。所以,“可靠”传输是指在网络基本正常的情况下数据收发必定成功,借用运维里的术语,大概就是“3 个 9”或者“4 个 9”的程度吧。
如果要100%保证数据收发成功就不能使用HTTP或者TCP协议,要使用各种消息中间件,如RabbitMQ、ZeroMQ、Kafka等。
HTTP 协议是一个应用层的协议。在 TCP/IP
诞生后的几十年里,出现了许多的应用层协议,但它们都仅关注很小的应用领域,局限在很少的应用场景,例如:
在通用的数据传输方面“完全不能打”。
HTTP 凭借着可携带任意头字段和实体数据的报文结构,以及连接控制、缓存代理等方便易用的特性,一出现就“技压群雄”,迅速成为了应用层里的“明星”协议。只要不太苛求性能,HTTP 几乎可以传递一切东西,满足各种需求,称得上是一个“万能”的协议。
HTTP 协议使用的是请求-应答通信模式。这个请求——应答模式是 HTTP 协议最根本的通信模型,通俗来讲就是“一发一收”“有来有去”,就像是写代码时的函数调用,只要填好请求头里的字段,“调用”后就会收到答复。
请求——应答模式也明确了 HTTP 协议里通信双方的定位:
当然,请求方和应答方的角色也不是绝对的,在浏览器——服务器的场景里,通常服务器都是应答方,但如果将它用作代理连接后端服务器,那么它就可能同时扮演请求方和应答方的角色。
HTTP 协议是无状态的。这个所谓的“状态”其实就是客户端或者服务器里保存的一些数据或者标志,记录了通信过程中的一些变化信息。
TCP 协议是有状态的:
这些“状态”就需要 TCP 在内部用一些数据结构去维护,可以简单地想象成是个标志量,标记当前所处的状态,例如:
HTTP 在整个协议里没有规定任何的“状态”,客户端和服务器永远是处在一种“无知”的状态。
“无状态”形象地来说就是“没有记忆能力”。
对比一下:
HTTP 是“灵活可扩展”的,虽然标准里没有规定“状态”,但完全能够在协议的框架里给它“打个补丁”,增加这个特性。
以前HTTP协议还有“无连接”的特点,即协议不保持连接状态,每次请求应答后都会关闭连接,这就和UDP几乎一模一样了。这会影响性能,在
HTTP/1.1
里就改成了总是默认启用keepalive长连接机制,所以现在的HTTP已经不再是“无连接”的了。
传输的实体数据可缓存可压缩、可分段获取数据、支持身份认证、支持国际化语言等。这些并不能算是 HTTP 的基本特点,因为这都是由第一个“灵活可扩展”的特点所衍生出来的。
限定在HTTP/1.1
版本。
HTTP 最重要也是最突出的优点是“简单、灵活、易于扩展”。“简单”蕴含了进化和扩展的可能性,所谓“少即是多”,“灵活和易于扩展”实际上是一体的,它们互为表里、相互促进,因为“灵活”所以才会“易于扩展”,而“易于扩展”又反过来让 HTTP 更加灵活,拥有更强的表现能力。
HTTP 协议里的请求方法、URI、状态码、原因短语、头字段等每一个核心组成要素都没有被“写死”,允许开发者任意定制、扩充或解释,给予了浏览器和服务器最大程度的信任和自由,也正好符合了互联网“自由与平等”的精神——缺什么功能自己加个字段或者错误码什么的补上就是了。
“请勿跟踪”所使用的头字段
DNT
(Do Not Track)就是一个很好的例子。它最早由 Mozilla 提出,用来保护用户隐私,防止网站监测追踪用户的偏好。不过可惜的是 DNT 从推出至今有差不多七八年的历史,但很多网站仍然选择“无视”DNT。虽然 DNT 基本失败了,但这也正说明 HTTP 协议是“灵活自由的”,不会受单方面势力的压制。类似的还有P3P
(Platfrom for Privacy Preferences Project)字段,用来控制网站对用户的隐私访问,当然也失败了。
“灵活、易于扩展”的特性还表现在 HTTP 对“可靠传输”的定义上,它不限制具体的下层协议,不仅可以使用 TCP、UNIX Domain Socket,还可以使用 SSL/TLS
,甚至是基于 UDP 的 QUIC,下层可以随意变化,而上层的语义则始终保持稳定。
HTTP 协议的另一大优点是“应用广泛”,软硬件环境都非常成熟。
随着互联网特别是移动互联网的普及,HTTP 的触角已经延伸到了世界的每一个角落,在开发领域 HTTP 协议也得到了广泛的支持。它并不限定某种编程语言或者操作系统,所以天然具有“跨语言、跨平台”的优越性。而且,因为本身的简单特性很容易实现,所以几乎所有的编程语言都有 HTTP 调用库和外围的开发测试工具。
HTTP 广泛应用的背后还有许多硬件基础设施支持,各个互联网公司和传统行业公司都不遗余力地“触网”,购买服务器开办网站,建设数据中心、CDN 和高速光纤,持续地优化上网体验,让 HTTP 运行的越来越顺畅。
“应用广泛”的这个优点也就决定了:无论是创业者还是求职者,无论是做网站服务器还是写应用客户端,HTTP 协议都是必须要掌握的基本技能。
出于安全的原因,绝大多数网站都封禁了80/8080以外的端口,只允许HTTP协议“穿透”,这也是造成HTTP流行的客观原因只之一。
“无状态”是一把“双刃剑”,它对于 HTTP 来说既是优点也是缺点。
优点:
缺点:
所以,HTTP 协议最好是既“无状态”又“有状态”,不过还真有“鱼和熊掌”两者兼得这样的好事,这就是“小甜饼”Cookie 技术。
明文传输也是一把“双刃剑”。
“明文”意思就是协议里的报文(准确地说是 header 部分)不使用二进制数据,而是用简单可阅读的文本形式。
HTTP/1.1以文本格式传输header,有严重的数据冗余,也影响了它的性能
。
对比 TCP、UDP 这样的二进制协议,它的优点显而易见,不需要借助任何外部工具,用浏览器、Wireshark 或者 tcpdump 抓包后,直接用肉眼就可以很容易地查看或者修改,为我们的开发调试工作带来极大的便利。
明文的缺点也是一样显而易见,HTTP 报文的所有信息都会暴露在“光天化日之下”,在漫长的传输链路的每一个环节上都毫无隐私可言,不怀好意的人只要侵入了这个链路里的某个设备,简单地“旁路”一下流量,就可以实现对通信的窥视。
黑客就是利用了 HTTP 明文传输的缺点,在公共场所架设一个 WiFi 热点开始“钓鱼”,诱骗网民上网。一旦你连上了这个 WiFi 热点,所有的流量都会被截获保存,里面如果有银行卡号、网站密码等敏感信息的话那就危险了,黑客拿到了这些数据就可以冒充你为所欲为。
与“明文”缺点相关但不完全等同的另一个缺点是“不安全”。
安全有很多的方面,明文只是“机密”方面的一个缺点,在“身份认证”和“完整性校验”这两方面 HTTP 也是欠缺的。
为了解决 HTTP 不安全的缺点,所以就出现了 HTTPS。
HTTP 的性能,“不算差,不够好”。HTTP 协议基于 TCP/IP
,并且使用了“请求 - 应答”的通信模式,所以性能的关键就在这两点上。
TCP 的性能是不差的,而且它已经被研究的很透,集成在操作系统内核里经过了细致的优化,足以应付大多数的场景。
为了解决这个问题,就诞生出了一个专门的研究课题“Web 性能优化”,HTTP 官方标准里就有“缓存”一章(RFC7234),非官方的“花招”就更多了,例如切图、数据内嵌与合并,域名分片、JavaScript“黑科技”等等。不过现在已经有了终极解决方案:
HTTP/2
和HTTP/3
。