文章目录

  • 前言
  • 一、Web技术简史
    • 1.1 Web浏览器技术简史
    • 1.2 Web服务器技术简史
  • 二、Web三大构建技术
    • 2.1 URL / URI
    • 2.2 HTML / XML
    • 2.3 HTTP / HTTPS
  • 更多文章:

前言

你知道当我们在网页浏览器( Web browser )的地址栏中输入网址( URL: Uniform Resource Locator )时, Web 页面是如何呈现的吗?(下图摘自文章:30 张图解 HTTP 常见的面试题)

Web 页面当然不能凭空显示出来,根据 Web 浏览器地址栏中指定的URL,Web 浏览器从 Web 服务器端获取文件资源(resource)等信息,从而显示出 Web 页面。像这种通过发送请求获取服务器资源的一方(比如 Chrome、Internet Explorer、Firefox 等),都可称为客户端(client);响应Web 客户端请求,并提供资源的一方(比如 Apache、Nginx、IIS 等),都可称为服务器端(server)。Web客户端向服务器请求资源,Web服务器响应资源的过程如下:

一、Web技术简史

1982年,美国国防部宣布TCP/IP为所有军用计算机联网的标准,并将TCP/IP协议部署到ARPANET中。1989 年 ,加州大学伯克利分校同意将为BSD UNIX开发的 TCP/IP 代码纳入公共领域,包括 IBM 在内的各种企业供应商在商业 TCP/IP 软件版本中包含此代码,这进一步推动了 TCP/IP 的传播。

1989年初,CERN(欧洲粒子物理研究所)中由 Tim Berners-Lee 领导的小组提交了一个针对 Internet 的新协议和一个使用该协议的文档系统,该小组将这个新系统命名为Word Wide Web(又被称为“WWW”、“W3”,中文名字为“万维网”、"环球网"等,常简称为Web),它的目的在于使全球的科学家能够利用 Internet 交流自己的工作文档,从而让远隔两地的研究者们共享知识。这个新系统被设计为允许 Internet 上任意一个用户都可以从许多文档服务计算机的数据库中搜索和获取文档,而且多个文档之间可通过超链接相互关联形成超文本(HyperText),最终连成可相互参阅的 WWW(World Wide Web,万维网)。

1990年底,Tim Berners-Lee 领导的小组已经构建了工作网络所需的所有工具:超文本传输协议(HTTP);超文本标记语言(HTML);第一个Web浏览器(名为WorldWideWeb,也是一个网页编辑器);第一个HTTP服务器软件(后来称为CERN httpd);第一个Web服务器主机(http://info.cern.ch)以及描述项目本身的第一个网页。第二年 Word Wide Web 系统被移植到了其他计算机平台并投入使用,Web技术的五大要素:HTML、HTTP、URL、Web浏览器、Web服务器,就此发明问世。1994年,Tim Berners-Lee决定成立万维网联盟(W3C),通过标准化流程来规范相关技术(HTTP、HTML等)的进一步发展。

  • URL(Uniform Resource Locator):解决了文档的命名和寻址识别问题;
  • HTTP(HyperText Transfer Protocol):解决了浏览器与服务器应用层之间的交流问题;
  • HTML(HyperText Markup Language):定义了超文本文档的表示格式;
  • Web浏览器:用于向服务器发起请求,并且解析收到的文档;
  • Web服务器:用于保存文档,并且响应来自浏览器的请求。

1.1 Web浏览器技术简史

1993 年,现代浏览器的祖先 NCSA(National Center for Supercomputer Applications,美国国家超级计算机应用中心)研发的Mosaic 问世了,1994年大家熟知的网景浏览器Netscape Navigator 1.0发布了,第二年Internet Explorer 1.0也发布了,由此进入Web互联网时代。(下图取自:网络的演变)

Web客户端的主要任务是展现信息内容,而HTML语言则是信息展现的最有效载体之一。1990年,Tim Berners-Lee领导的小组构建的HTML 1.0超文本标记语言是继承自SGML(Standard Generalized Markup Language)标准通用标记语言的,可以实现文本与文本之间通过超链接相互关联(这种通过超链接实现文本关联的技术称为超文本技术),由于SGML过于复杂且不利于信息的传递和解析,Tim Berners-Lee对其进行了大刀阔斧的简化和完善,一种为Web量身定制的语言 HTML 就诞生了。

最初的HTML语言只能在浏览器中展现静态的文本或图像信息,这满足不了人们对信息丰富性和多样性的强烈需求,于是由静态技术向动态技术的转变成为了Web客户端技术演进的永恒定律。1996年,著名的Netscape浏览器在其2.0版中增加了对JavaScript的支持,Microsoft的IE 3.0也在这一年开始支持Java技术,喜欢动画、交互操作、客户端应用的开发人员可以用Java或JavaScript语言随心所欲地丰富HTML页面的功能了。

真正让HTML页面又酷又炫、动感无限的是CSS(Cascading Style Sheets)技术。1996年底,W3C提出了CSS的建议标准,随后 IE 3.0 和Netscape 4.0 引入了对CSS的支持,CSS大大提高了开发者对信息展现格式的控制能力,让HTML页面中的各种要素"活动"了起来。

1.2 Web服务器技术简史

1993年,同浏览器NCSA Mosaic一起问世的还有对应的服务器NCSA httpd,紧随其后的是现在已然成为 Web 服务器标准之一的Apache(Apache httpd),当时它以 Apache 0.2 的姿态出现在世人眼前,到目前依然是全球最受欢迎的Web服务器软件。微软的 IIS (Internet Information Services)也是最早出现的Web服务器软件之一,其早期使用的是Gopher通信协议,直到IIS 5.0版本才切换为HTTP通信协议,随后成为全球第二大最受欢迎的Web服务器软件,但从2014年开始被新晋的Nginx反超且差距越拉越大。截止到2020年,主流Web浏览器与Web服务器软件的市场占有率对比如下:

最早的Web服务器简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,此时Web服务器只能提供静态文本或图片的共享服务。可随着 Web 越来越普及,仅靠这样的做法已不足以应对所有的需求,更需要引入由程序创建 HTML 内容的做法。第一种真正使服务器能根据运行时的具体情况,动态生成HTML页面的技术是大名鼎鼎的CGI(Common Gateway Interface)技术,CGI 1.0的标准草案于1993年由NCSA提出。

CGI定义了Web服务器与应用程序间通信的接口标准,使Web服务器可以通过CGI程序执行Web应用程序,完成动态请求的处理,然后拼接成HTML代码返回给Web服务器,最后再将生成的HTML代码响应给Web浏览器。CGI程序通过环境变量和标准输入获得请求的各种参数信息,通过标准输出返回应答;服务器并不关心CGI程序是用什么语言编写的,它仅通过环境变量和标准输入、输出与CGI程序交互。

每当有一个请求对应到一个CGI程序时,服务器就启动一个进程执行这个CGI程序,因此CGI程序对主机的资源消耗比较大(想想如果有1000个并发请求会怎么样),同时它的响应速度也会比较慢(进程的启动比较花时间)。所以人们开始寻找CGI的替代者,这导致了FastCGI技术的出现。简单来说,FastCGI本质上就是一个常驻内存的进程池技术,由调度器负责将传递过来的CGI请求发送给处理CGI的handler进程来处理,在一个请求处理完成之后,该处理进程不销毁,继续等待下一个请求的到来。

1994年,Rasmus Lerdorf发明了专用于Web服务端编程的PHP(Personal Home Page Tools)语言,与以往的CGI程序不同,PHP可以把程序嵌入到HTML代码中去执行,不仅能更好的组织Web应用的内容,而且执行效率比外部程序更高,Web应用的开发者可以用一种更加简便、快捷的方式实现动态Web功能。

1996年,Microsoft借鉴PHP的思想,在其Web服务器IIS 3.0中引入了ASP(Active Server Pages)技术(使用的脚本语言是VBScript和JavaScript),并于2002年被ASP.NET取代。1997年,以Sun公司为首的Java阵营发布了Servlet技术,第二年JSP(Java Server Pages)技术诞生,Servlet和JSP的组合(还可以加上JavaBean技术)让Java开发者同时拥有了类似CGI程序的集中处理功能和类似PHP的HTML嵌入功能,Java的运行时编译技术也大大提高了Servlet和JSP的执行效率。随着Web服务器端动态页面技术的普及,社交网络、论坛、电子商务、信息查询、全文检索等各式各样的Web应用蓬勃兴起,人们终于可以享受到信息检索、信息交换、信息处理等更为便捷的信息服务了,万维网也开始快速发展。

Servlet程序与CGI程序的明显不同就是:

  • Servlet 运行在与 Web 服务器程序相同的进程中(Servlet 的运行环境叫做 Web 容器或 Servlet 容器),Servlet 常驻内存,在每次请求时可从线程池启动相对进程级别更为轻量的线程,程序的执行效率从而变得更高;
  • CGI 运行在与 Web 服务器程序不同的进程中,每次请求启动一个新的CGI 进程,即便是改进后的FastCGI 常驻内存,程序的执行效率依然跟Servlet 有不小的差距。

服务器端网页动态交互功能的不断丰富,伴随的是代码逻辑的复杂度快速上升,同时Web客户端形态越来越多样(比如手机、平板、电脑、智能电视等),Web应用需要提供的服务越来越复杂,Web应用中的网页视图表现模块与业务数据处理模块逐渐分离,向着高内聚、松耦合的方向发展。为了更好的管理前后端代码逻辑,出现了大量的MVC(Model–View–Controller)开发框架:

  • View:向控制器提交数据和为模型提供数据显示,侧重于数据的可视化呈现效果;
  • Model:用于存取数据以及处理用户请求的业务逻辑;
  • Controller:根据视图提出的请求判断将请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示;


MVC框架在一定程度上实现了数据显示与数据处理的分离,前端可以针对不同的Web客户端形态开发不同的View视图模板,后端可以针对不同的业务类型开发不同的 Model 数据模型,中间由Controller 完成两部分之间的数据转交与匹配。但MVC框架中的View与Model并没有完全分离,二者之间仍有相当的耦合,不利于更复杂代码逻辑的开发。随后出现的MVP(Model–View–Presenter)框架初步实现了View与Model的完全分离,但Presenter 比原来的Controller 代码逻辑更加复杂;MVVM(Model-View-ViewModel)框架采用事件监听与数据双向绑定的方法,简化了ViewModel 与 View 的交互逻辑,不仅实现了View 与Model 的完全分离,而且提高了 View 与Model 之间的数据同步效率。

Web最初的设计理念就是信息的共享,从Web 1.0 信息的静态单向呈现到Web 2.0 信息的动态双向交互,Web信息的流动和处理效率越来越高。我们设想一下,Web未来会是什么形态呢?W3C已经明确告诉我们,Web的未来是语义化的Web(Semantic Web)。今天的Web可以自如地生成、传递和展现各式各样的信息,但它还只是一个信息的"容器",很难揭示出信息本身的内容和特性。与此相对的是,未来的语义化Web 3.0是一种懂得信息内容的Web,是真正的"信息管理员"。

二、Web三大构建技术

2.1 URL / URI

网络资源是如何唯一标识自身的呢?还记得前面介绍TCP/IP协议时,每个IP地址或域名标识Internet上唯一的一个主机,我们计算机中每个文件都是被文件系统管理的,有一个唯一的文件路径,将某主机域名与某资源所在该主机的文件路径连起来不就可以唯一标识并定位该资源在Internet上的存储位置了吗?统一资源定位符URL也正是按照这个逻辑标识某特定资源的,语法关系与标识格式(在RFC 3986中定义)如下:

字段名功能描述
协议名可以是http、https、ftp等,不区分大小写
登录认证信息从服务器获取资源需要的身份权限信息,该字段为可选项
服务器地址可以是IPv4、IPv6、DNS可解析的域名等,用来标识Internet上唯一的服务器主机
服务器端口号指定服务器连接的网络端口号,http协议默认端口号80,https协议默认端口号443
带层次的文件路径指定服务器上的文件路径来定位特指的资源,与 Linux的文件目录结构相似
查询字符串针对已指定的文件路径内的资源,可以使用查询字符串传入任意参数,为可选项
片段标识符可标记出已获取资源中的子资源(文档内的某个位置),该字段为可选项

我们还经常听到URI(Uniform Resource Identifier,统一资源标识符),它和URL是一样的吗?实际上URI 可以看作URL的超集,也即URL是URI 的子集,二者的关系如下:

这里又出来一个URN(Universal Resource Name,统一资源名称),这又是什么呢?我们使用的身份证号,购买图书的ISBN编号等可以唯一标识一个物体的名称都是URN。

URI、URL、URN三者的对比如下表所示(参考博客:标识互联网上的资源和分清 URI、URL 和 URN):

名称功能描述示例
URI用来标识抽象或物理资源的一个紧凑字符串https://developer.mozilla/en-US/docs/Learn
tel:+1-816-555-1212
git@github:mdn/browser-compat-data.git
ftp://example/resource.txt
urn:isbn:9780141036144
URL一种定位资源的主要访问机制的字符串,
唯一标识并定位该资源在Internet上的存储位置
https://developer.mozilla
https://developer.mozilla/en-US/docs/Learn/
https://developer.mozilla/en-US/search?q=URL
URN通过特定命名空间中的唯一名称或ID来标识资源,
但不包括访问该资源的位置或方式
urn:isbn:9780141036144
urn:ietf:rfc:7230

就像Linux一切皆文件的思想一样,Web网络上一切皆资源,比如文本html / xml / json、图片jpeg / png / gif、音视频avi / wav / mpeg、压缩文件gz / tar / zip、二进制文件 等(可以参考MIME 资源类型),URL就可以唯一标识并定位某资源存储的位置,以便对该资源进行增、删、改、查等操作。

2.2 HTML / XML

前面谈到Web最初的设计理念就是借助多文档之间相互关联形成的超文本(HyperText),连成可相互参阅的 World Wide Web 。文档之间如何关联呢?超文本又是什么呢?

有了前面URL 统一资源定位符的概念,就可以使用URL 来定位并找到某一资源(比如文档)了,如果我们把文档A的URL 放到文档B中,就相当于文档A被关联到文档B中了,也即通过文档B中保存的文档A的URL(也称为文档A的超链接)就可以找到并访问文档A。如果每个文档中都保存了多个相关文档的URL,就可以通过URL以超链接的形式将相关文档关联起来,形成一张信息网,这种包含其它文本URL的文本称为超文本(HyperText)。

我们通过Web浏览器看到的一个个网页实际上就是一个个超文本,Tim Berners-Lee在设计Word Wide Web时,为了描述网页的结构,开发的HTML(HyperText Markup Language)是一种在Web 浏览器中显示超文本页面的标准标记语言。HTML最初是用来描述多文档之间相互关联形成的超文本结构,随着图像、音频、视频、动画等多媒体资源的普及,逐渐扩展为用来描述多媒体资源之间相互关联形成的超媒体结构(URL也可标识并定位任意多媒体资源)。

Tim Berners-Lee开发的初版HTML并没有形成规范,后于1993年发表的第一个HTML规范提案(HTML 1.0)也因为很多地方模糊不清而没有被采用。1995年,由 IETF(Internet Engineering Task Force)发布的HTML 2.0才算是第一个HTML正式规范被普及应用(最初定义在RFC1866中,最近更新在RFC2070中)。随后,Tim Berners-Lee牵头成立的W3C万维网联合会取代IETF的角色,成为HTML标准的制定者,并先后于1997年发布HTML 3.2版本和HTML 4.0版本,于1999年发布了HTML 4.01版本,该版本在很长时间内被普及应用。

如果说HTML语言给Web世界赋予了无限生机的话,那么,XML语言的出现大概就可以算成是Web的一次新生了。按照Tim Berners-Lee的说法,Web是一个"信息空间"。HTML语言具有较强的表现力,但也存在结构过于灵活、语法不规范的弱点。当信息都以HTML语言的面貌出现时,Web这个信息空间是杂乱无章、没有秩序的。为了让Web世界里的所有信息都有章可循、有法可依,我们需要一种更为规范、更能够体现信息特点的语言。

1996年,W3C在SGML语言的基础上,提出了XML(eXtensible Markup Language)语言草案,并于1998年正式发布了XML 1.0标准。XML语言对信息的格式和表达方法做了最大程度的规范,应用软件可以按照统一的方式处理所有XML信息。这样一来,信息在整个Web世界里的共享和交换就有了技术上的保障,HTML语言关心的是信息的表现形式,而XML语言关心的是信息本身的格式和数据内容。从这个意义上说,XML语言不但可以将客户端的信息展现技术提高到一个新的层次,而且可以显著提高服务端的信息获取、生成、发布和共享能力。为了将XML信息转换为HTML等不同的信息展现形式,W3C于1999年制定出了XSLT(eXtensible Stylesheet Language Transformations)标准,IE 5.0在同一年就增加了对XML和XSLT的支持。

由于HTML是一种松散的、不能够适应社会发展需要的标记语言,因此W3C组织在2000年,以XML为根本重构了HTML 4.01,取名为:XHTML(eXtensible HyperText Markup Language) 1.0。XHTML 1.0相比HTML 4.0.1并没有引入任何新标签或属性,唯一的区别是语法,HTML 对语法比较随便,而 XHTML 则要求 XML 般的严格语法。自此,W3C 逐渐将未来发展的重心放到XHTML 2.0上,希望将 Web 带向 XML 的光明未来。虽然 XHTML 2 听上去和 XHTML 1 类似,它们却有很多差别,XHTML 2 不向前兼容,甚至不兼容之前的 HTML,这对于Web服务提供商实在是一场灾难。

W3C 闭门造车的作风引起了一些人的不满,Mozilla、Opera和Apple在 2004 年,为了开发与现有浏览器向后兼容的技术,成立了WHATWG(Web Hypertext Application Technology Working Group),开始制定Web Forms 2.0 和 Web Apps 1.0标准,这两个规范后来被合并到HTML 5标准中。2006年,Tim Berners-Lee 表示从 HTML 走向 XML 的路是行不通的,随后W3C组建了一个新的HTML工作组,并选择WHATWG 的成果作为基础,和WHATWG一同制定HTML 5的标准规范。 2008年,HTML 5第一份正式草案公布,各大浏览器厂商(WHATWG成员,包括后加入的Google和Microsoft)从第一份草案就开始伴随HTML 5的完善过程逐步增加对其新特性的支持,直到2014年,HTML 5正式标准规范才最终制定完成并发布。

HTML 5被设计为跨平台的,可以在不同类型的硬件(PC、平板、手机、电视机等等)上运行,并且拥有新的语义、图形以及多媒体元素(比如video、audio和canvas 等),可以承载丰富的 web 内容而无需额外插件。HTML 5提供的新元素和新的 API 简化了 web 应用程序的搭建,可以真正改变用户与文档的交互方式,这些特性是XHTML不能满足的(HTML 5支持XHTML 1.0的严格语法),伴随移动互联网的快速发展,HTML 5目前已成为HTML技术的主流标准。

什么是标记语言呢?下面以主流的HTML 5语法,展示HTML标记语言的基本结构:

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <title>你好</title>
 </head>
 <body>
   <p>你好,HTML!</p>
 </body>
</html>

标记语言(Markup Language)用一套“标记”来“注释”(annotate)普通文本,对HTML来说,这套标记就是各种标签(tag),比如上面被左右尖括号<和>括起来的部分。浏览器理解这套标签的含义,并据此解读HTML文档,浏览器对HTML文档进行解析后得到一个抽象数据结构:DOM(Document Object Model),以上面的HTML文档为例,它对应的DOM树是:

其中:

  • 根节点document:代表整个HTML文档;
  • DOCTYPE html:文档类型声明(Document Type Declaration),上例声明的文档类型是HTML 5;
  • 每个HTML标签,如html、head、meta等,都对应着一个节点 — 这类节点称为元素(Element);
  • 标签的每个属性都对应着它的一个子节点,比如 meta标签的charset属性对应着meta元素的一个子节点,这类节点称为属性(Attribute)节点;
  • 标签包含的文字对应着它的一个子节点,比如 p标签包含的文字“你好,HTML!”对应着p元素的一个子节点,这类节点称为文字(Text)节点;
  • 标签直接包含的每个标签都对应着它的一个子节点,比如 html标签包含的 head标签和 body标签,分别对应着html元素的两个子节点head和body。

HTML支持的主要标签如下(图片取自博客:HTML思维导图):

随着HTML标签和属性的丰富,HTML的样式代码逐渐被分离出来形成了CSS层叠样式表,HTML样式代码与内容代码分离后,HTML代码仅含有网页的“内容”(如文本和图片),而CSS指定了这些内容的视觉效果。同样的,HTML负责动态行为的代码也逐渐被分离出来作为单独的JavaScript 脚本,内容(HTML)、样式(CSS)和行为(JavaScript)彼此独立又相互关联,共同在Web页面上展现出更加动感酷炫的多媒体信息。下面给出一个简单的示例,在一个文件夹内分别创建三个文件:hello.html、hello.css、hello.js,这三个文件的代码分别如下:

hello.html代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>你好</title>
    <link rel="stylesheet" href="hello.css">
  </head>
  <body>
    <p>你好,HTML!</p>
    <button id="btn1">点我</button>
    <script src="hello.js"></script>
  </body>
</html>

hello.css代码:

p{
    color: blue;
    font-size: 2em;
}

hello.js代码:

var btn = document.getElementById('btn1');
btn.onclick = function() {
  document.body.innerHTML = '<h1>你好,JavaScript!</h1>';
};

在hello.html代码中,通过link标签属性关联hello.css代码,通过script标签属性关联hello.js代码,用浏览器打开hello.html文件即可看到hello.html代码中定义的内容、hello.css代码中定义的样式、hello.js代码中定义的动作/行为,hello.js代码中对hello.html的访问主要是通过DOM方法完成的。

2.3 HTTP / HTTPS

有了Web客户端可以解读并呈现信息的HTML文档,也知道了该HTML页面的URL,Web客户端怎么通过 Internet 从Web服务器获取该页面资源呢?还记得TCP/IP经典的分层模型吗?

Web 使用一种名为 HTTP(HyperText Transfer Protocol,超文本传输协议)的应用层协议作为规范,借助底层的TCP/IP协议完成客户端与服务器端之间各种资源的传输,可以说Web 是建立在 HTTP 协议上通信的。

HTTP/1.0协议标准被正式公布是在 1996 年,并记载于 RFC1945。Tim Berners-Lee 于1990年实现的HTTP协议并没有作为正式标准被建立,将其称为HTTP/0.9(只实现了GET方法),意为HTTP/1.0之前的版本。

HTTP/1.0协议作为第一版正式标准,只实现了基本的功能,通信效率比较低。于是在第二年(1997年)又发布了HTTP/1.1 协议标准,提高了 HTTP/1.0 的传输效率,同时扩展了部分功能。直到今天,HTTP/1.1 仍是主流的协议版本(当初的标准是 RFC2068,之后发布了修订版 RFC2616)。HTTP/1.1 相比 HTTP/1.0 的改进主要有以下几个方面:

  • 引入了持久连接( persistent connection):即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive;
  • 引入了管道机制( pipelining):即在同一个TCP连接里,客户端可以同时发送多个请求,进一步改进了HTTP协议的效率;
  • 新增请求方法:OPTIONS、PUT、PATCH、DELETE、TRACE 和 CONNECT 方法;
  • 新增首部字段:比如Host字段支持一台主机上配置多个虚拟主机,Range字段支持请求部分页面内容等。

HTTP是无连接协议,Web客户端与Web服务器之间的连接由TCP协议负责管理,HTTP/1.0每次HTTP请求/响应都需要打开/关闭一次TCP连接,HTTP/1.1则可以在每次TCP连接期间完成多次HTTP请求/响应;而且多个HTTP请求可以以流水线形式发送,并不需要等收到对应的响应再发送下一个请求。
Web客户端虽然支持以流水线形式连续发送多个HTTP请求,但Web服务端对收到的多个HTTP请求仍然是按顺序处理的,假如前面有一个HTTP请求因为某种原因被阻塞了,后面排队的所有请求也会一同被阻塞,这会导致Web客户端一直请求不到数据,造成“队头阻塞”。

HTTP也是无状态协议,它不对之前发生过的请求和响应的状态进行管理,也即无法根据之前的状态进行本次的请求处理。无状态的优点是简单快速,减少服务器资源消耗;缺点就是对于要求登录认证的Web页面(比如个人博客、网银账户等)无法进行状态管理,每次跳转到新页面都需要再次登录,或在请求报文中附件参数来管理登录状态。为了更方便进行状态管理,引入了Cookie技术,通过在请求和响应报文中写入 Cookie 信息来管理客户端的登录状态。

TCP/IP协议每一层都有自己的数据帧或数据报格式,HTTP协议也不例外。由于HTTP协议基于Client/Server(或Browser/Server)结构,HTTP的报文也分为两种:客户端向服务器发送HTTP请求报文;服务器向客户端返回HTTP响应报文。下面以目前主流使用的HTTP/1.1为例分别展示HTTP请求报文与响应报文的结构:

HTTP 请求报文包括请求行、请求头部、空行、报文主体等部分构成,请求行包括请求方法、URL、协议版本三部分,请求首部主要包括请求的各种条件或属性,空行是为了分割首部与主体,报文主体则包含应被发送的数据(html文档)。HTTP响应报文包括状态行、响应头部、空行、报文主体等部分构成,响应行包括协议版本、状态码、状态原因短语三部分,响应头部主要包括响应的各种条件或属性,空行用于分割首部和主体,报文主体则包含应被发送的数据(html文档)。

HTTP请求—响应的过程可以通过 curl 命令展示,比如在cmd命令行窗口输入"curl -v http://www.baidu/index.html",返回结果如下:

C:\Users\Administrator>curl -v http://www.baidu/index.html
*   Trying 61.135.169.125...
* TCP_NODELAY set
* Connected to www.baidu (61.135.169.125) port 80 (#0)
> GET /index.html HTTP/1.1
> Host: www.baidu
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Connection: keep-alive
< Content-Length: 2381
< Content-Type: text/html
< Date: Mon, 27 Apr 2020 03:34:17 GMT
< Etag: "588604c4-94d"
< Last-Modified: Mon, 23 Jan 2017 13:27:32 GMT
< Pragma: no-cache
< Server: bfe/1.0.8.18
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu; path=/
<
<!DOCTYPE html>
<!--STATUS OK-->
<html>
......
</html>
* Connection #0 to host www.baidu left intact

其中,“> ”开头的行是客户端发出的请求,“< ”开头的行是服务器的应答(应答的主体部分,也即html页面内容,使用“…”表示了)。“* ”开头的行是HTTP连接建立以前curl输出的一些诊断信息,我们可以看到curl通过DNS查找到“www.baidu”对应的IP:61.135.169.125,port:80。

HTTP请求最常用的方法是GET和POST,上面的示例是使用GET方法请求百度首页信息,通信协议版本为HTTP/1.1,URL为"/index.html" (资源在特定主机内的存储路径,需要与请求头部Host字段的主机名配合使用)。请求头部User-Agent字段为请求客户端名称,Accept字段为请求客户端可接收并解析的资源类型。

  • GET方法:请求指定的页面资源,页面信息包含在返回的应答报文主体中;
  • POST方法:向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求报文主体中。

上例中HTTP响应报文的响应状态码200表示资源请求成功,响应头的Connection字段值keep-alive意为持久连接,Content-Type字段值text/html表示返回的资源是html文本类型,Content-Length字段则表示文本长度(单位bytes),字段Set-Cookie则是服务器生成并添加的Cookie信息(方便管理客户端的登录/认证状态),最后的应答报文主体则是请求的html页面内容。

HTTP 协议比较简单,数据是以明文形式传输的,这就存在信息泄露、信息篡改、信息伪造等风险,比如我们登录网银账号时,肯定需要对传输的信息进行加密处理。我们留心地址栏的话也会发现,对于需要登陆的网站一般都以 https 开头(而且有一把琐的标识),这个https协议相比http协议增加了信息加密层 SSL/TLS,二者的协议分层结构对比如下:

HTTPS 协议新增的SSL/TLS层具有信息加密、身份认证、信息完整性校验等功能,可以保证信息传输的安全。但因为HTTPS协议新增了SSL/TLS层,在传输数据前除了需要完成TCP的三次握手,还需要完成SSL/TLS的握手过程。为了与HTTP协议相区分,HTTPS协议端口号改为了443(HTTP协议端口号为80)。

随着网络数据和带宽的快速增长,HTTP/1.1也遇到了性能瓶颈,以Google为首的Web服务商不断改进优化HTTP协议,比如Google于2012年发布的SPDY(speedy)以会话层的形式加入,可以为请求报文赋予优先级解决对头阻塞问题,可以压缩HTTP首部提高通信效率,支持服务器主动向客户端推送数据的功能等,SPDY后来成为HTTP/2标准开发的起点。2015年,HTTP/2标准规范发布于RFC7540,HTTP/2相比HTTP/1.1主要的性能改进如下( HTTP/2 的规范并不明确要求 TLS,也支持以明文通信,但主流浏览器都不支持基于非 TLS 的 HTTP/2,因此 TLS 层也就在事实上相当于是强制性的,HTTP/2 也成为一次推动全网加密通信发展的机会):

  • 头部压缩HPACK:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了;
  • 二进制格式传输:HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,这样虽然对人不友好,但计算机可以直接解析二进制报文,提高了数据处理速度;
  • 数据流管理:HTTP/2 的数据包不是按顺序发送的,同一个连接里面连续的数据包可能属于不同的回应,每个请求或回应的所有数据包称为一个数据流(Stream),每个数据流都标记着一个独一无二的编号,客户端可以指定数据流的优先级;
  • 多路复用:HTTP/2 可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应(HTTP/1.1需要按照顺序响应),解决了队头阻塞的问题,降低了延迟,大幅度提高了连接的利用率;
  • 服务器推送:HTTP/2 在一定程度上改善了传统的「请求 - 应答」工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。

HTTP/2 协议 主要的问题在于:多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的。所以一旦发生了丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。这是基于 TCP 传输层的问题,所以 HTTP/3 把 HTTP 下层的 TCP 协议改成了 UDP。UDP协议不管理数据包,因此不会出现TCP丢包重传的问题,但UDP是不可靠的传输,Google基于UDP开发了QUIC协议有自己的一套机制可以保证传输的可靠性的,当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响。2016年,IETF(Internet Engineering Task Force)成立了QUIC工作组,并在2018年将 QUIC 上的 HTTP 映射称为 “HTTP/3”,直到2020年HTTP/3仍处于草案更新阶段,距离正式标准发布估计还有一段不短的路要走。

HTTP/3 协议使用UDP+QUIC代替TCP协议管理数据流的可靠传输,同时将报文头部压缩算法升级为QPACK、加密层协议升级为TLS 1.3版本。由于QUIC 协议相当于 TCP + TLS 1.3 合并,TCP 握手包可以携带TLS 握手包数据,相比HTTPS 建立连接时的六次握手过程(TCP 三次握手 + TLS 1.3 三次握手),QUIC只需要三次握手过程(每个建立连接的握手包携带一个TLS 协商密钥的握手包)即可,减少了交互次数。

更多文章:

  • 《Web技术(二):图解HTTP + HTTPS + HSTS》
  • 《Web技术(五):HTTP/2 是如何解决HTTP/1.1 性能瓶颈的?》
  • 《Web技术(六):QUIC 是如何解决TCP 性能瓶颈的?》
  • 《TCP/IP协议栈之LwIP(十)—Socket API编程》
  • 《数据结构与算法分析(九)— 哈希算法能用来干啥?》
  • 《Web应用系统架构演进过程》
  • 《Bluetooth 协议栈设计与演进(Core_v5.2 + 6LoWPAN + Mesh)》

更多推荐

Web技术(一):互联网的设计与演化(URL + HTML + HTTP)