跳转至

第6章 HTTP

第 6 章

HTTP

HTTP 是学习 JavaWeb 开发的基石,绝大多数的 Web 开发,都是构建在 HTTP 之上的。Web 开发过程涉及客户端与服务端的交互,这一点我们需要对 HTTP 有深入的了解。理解和掌握 HTTP,将有助于我们更好地学习和掌握 Servlet 技术,以及其他相关的 Web 开发技术。本章主要介绍 HTTP 会话方式、报文,以及浏览器监听 HTTP 的相关操作等。

6.1 HTTP 简介

HTTP 全称是 HyperText Transfer Protocol,原意是 “超文本转移协议”,最初引入国内被翻译成 “超文本传输协议”。本书在后面部分均称之为 “超文本传输协议”。超文本的概念是泰德・纳尔森(Ted Nelson)在 1960 年代提出的。进入哈佛大学后,纳尔森一直致力于超文本协议和该项目的研究,但他从未公开发表过资料。1989 年,蒂姆・伯纳斯・李(Tim Berners Lee)在 CERN(欧洲原子核研究委员会,全称为 European Organization for Nuclear Research)担任软件咨询师的时候,开发了一套程序,奠定了万维网(WWW,全称为 World Wide Web)的基础。1990 年 12 月,超文本在 CERN 首次上线。1991 年夏天,继 Telnet 等协议之后,超文本转移协议成为互联网诸多协议的一分子。

当时,Telnet 协议解决了一台计算机和另外一台计算机之间一对一的控制型通信的要求。邮件协议解决了一个发件人向少量人员发送信息的通信要求。文件传输协议解决一台计算机从另外一台计算机批量获取文件的通信要求,但是它不具备一边获取文件一边显示文件或对文件进行某种处理的功能。新闻传输协议解决了一对多新闻广播的通信要求。而超文本要解决的通信要求是:在一台计算机上获取并显示存放在多台计算机里的文本、数据、图片和其他类型的文件。它主要包含两大部分,超文本转移协议和超文本标记语言(HTML)。随后,HTTP、HTML 以及浏览器的诞生,给互联网的普及带来了飞跃进展。

超文本传输协议是我们浏览网页、观看在线视频或者听在线音乐等必须遵守的规则。正是在这样的规则下,浏览器才能向万维网服务器端发送万维网文档请求,然后服务器端会将请求的文档发送回浏览器。在浏览器和服务器之间的请求和响应的交互,必须按照规定的格式和规则进行,这些格式和规则构成了超文本传输协议。

6.1.1 什么是 HTTP

HTTP 是一个属于应用层的面向对象的协议。它适用于分布式超媒体信息系统,经过十几年的使用与发展,不断完善和扩展。由于其简洁、快速的方式,是现今在 WWW 上应用得最多的协议,本书基于 HTTP1.1 版本。值得一提的是,HTTP1.1 后支持可持续连接。HTTP 作为应用层协议,详细规定了浏览器和万维网服务器端之间互相通信的规则,是通过因特网传送万维网文档的数据传送协议。

客户端与服务端通信时,传输的内容我们称之为报文。HTTP 是一个通信规则,这个规则规定了客户端发送给服务器端的报文格式,也规定了服务器端发送给客户端的报文格式。HTTP 包括请求和响应两种报文,客户端发送给服务器端的报文称为 “请求报文”,服务器端发送给客户端的报文称为 “响应报文”。

类比生活中的案例,HTTP 可以看作租房时签署的租房协议,用于规范多方需遵守的规则,又好比以前人们通过书信方式通信时,信封上要遵循的规范。例如,用户(客户端)访问京东网页(服务器端)进行购物,就是客户端和服务器端之间互相通信的过程。用户给服务器端写信,即用户向服务器端发送请求,请求的全部内容被称为请求报文;反之,服务器端给用户回信,即服务器端对用户做出响应,响应的全部内容被称为响应报文。而信(报文)是有格式的,由 HTTP 来规定,也就是说 HTTP 规定互联网之间如何传输数据。

HTTP 也是一个基于请求 / 响应模式的,无状态的协议。什么是无状态呢?无状态是指协议对于事务处理没有记忆能力,就是说客户端发出一个请求,服务端对其响应,此时,如果同一客户端又发出一个请求,服务器端并不能记住当前请求是由刚才的客户端发出的请求,这就是所谓的无状态的含义。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器端不需要先前信息时,它的应答就较快。

6.1.2 会话方式

浏览器与服务器之间的通信过程,如图 6-1 所示。一次完整的请求响应通常需要经历以下四个步骤。

步骤一:客户端和服务器端建立连接。

步骤二:客户端发送请求数据到服务器端。

步骤三:服务器端接收请求后进行处理,然后将处理结果响应给客户端。

42f7cc61002df917c81dbe6245b8fa36a6ca4d393f65fd5c4ca4673107490ba6.jpg

步骤四:关闭客户端和服务器端的连接(HTTP1.1 后不会立即关闭)。

浏览器与 Web 服务器的连接过程是短暂的,每次连接只处理一个请求和响应。对每一个页面的访问,浏览器与 Web 服务器都要建立一次单独的连接。浏览器到 Web 服务器之间的所有通信都是完全独立分开的请求和响应对。

6.1.3 不同版本的区别

在 HTTP1.0 中,如果浏览器请求一个带有图片的网页,会由于下载图片而与服务器端之间开启一个新的连接;但在 HTTP1.1 中,允许浏览器在拿到当前请求对应的全部资源后再断开连接,这样做可以提高效率,如图 6-2 所示。

988901afa6b3dbed247fc903d2500bc6a5487f0f0083a60887c7734c8ce1eef9.jpg

HTTP 协议一共包含 3 个版本,分别是 HTTP1.0、HTTP1.1 和 HTTP2.0。HTTP1.0 规定了浏览器与服务器端之间是短暂的连接,每次请求都要建立一个连接,称为 TCP 连接。当两端处理完数据后立刻断开连接,因此这是一个无状态的请求,服务器端不去记录客户端以前的请求。

而 HTTP1.1 继承了 HTTP1.0 简单的特点,并在此基础上规定了长连接的协议。那么我们应该如何实现长连接呢?其实,HTTP1.1 在 HTTP1.0 的基础上增加了一个 connection 字段,其值为 keep-alive,代表连接不断开,这种连接方式提高了网络利用率。如果不想用长连接,可以设置 connetion 的值为 false,关闭长连接。HTTP1.1 也支持管道化技术,即所使用的并行技术,需要注意的是,并行的实现要求服务器端必须按照客户端请求的顺序依次返回响应,该版本是我们主讲版本。

HTTP2.0 在 HTTP1.1 的基础上增加了二进制,改进了 HTTP1.1 的性能,突破了传输过程中的瓶颈。由于该规范相比 HTTP1.1 和 HTTP1.0 而言改动较大,所以不再延续之前为 HTTP1.3 而直接改成了 HTTP2.0,HTTP2.0 支持多路复用,连接共享,并且头部做了压缩,支持服务器端主动推送。

6.2 报文

HTTP 报文是 HTTP 应用程序之间发送的数据块,以一些文本形式的元信息开头,这些信息描述了报文的内容及含义,后面跟着可选的数据部分。HTTP 报文是面向文本的,报文中的每一个字段都是一些 ASCII 码串,各个字段的长度是不确定的。

报文的组成包括三部分,报文首部、空行和报文主体,如图 6-3 所示。

图 6-3 报文的组成

报文首部【报文首部】 服务器端或客户端需处理的请求或响应的内容及属性
空行 (CR+LF)【CR+LF】 CR (Carriage Return, 回车符: 16进制0×0d) LF (Line Feed, 换行符: 16进制0×0a)
报文主体【报文主体】 应被发送的数据

HTTP 报文包括请求报文和响应报文两类。这些报文在客户端、服务器端和代理之间流动。一次 HTTP 请求,HTTP 报文会从 “客户端” 流到 “代理” 再流到 “服务器端”,在服务器端完成工作之后,报文又会从 “服务器端” 流到 “代理” 再流到 “客户端”。请求报文指浏览器发给服务器端的内容。响应报文指服务器端发回给浏览器的内容。下面分别对请求报文和响应报文展开介绍。

6.2.1 请求报文

请求报文一般包括四部分,分别为请求行(Request Line)、请求头(Headers)、空行(Blank Line)、请求体(Request Body),如图 6-4 所示。

4315954ed16894b50cc7fd2aedfe054e5ed295e0747e5d1dd80d64d86d1525e8.jpg

在请求报文中,开始行就是请求行。请求行包括三部分,分别为请求方式、访问路径和 HTTP 版本号。请求头包含很多内容,如 Content-Type(内容类型)、Content-Length(指定 Body 长度)、User-Agent(用户代理)等。请求体就是报文的主要数据部分,可以是任意数据类型的数据。比如请求体中包含了要发给服务器端的数据,响应体中装载了要返回给客户端的数据。

请求报文的格式如下。

HTTP 中包括以下 8 种请求方式,HTTP1.0 定义了 GET、POST、HEAD 3 种请求方式,HTTP1.1 则新增了 OPTIONS、PUT、DELETE、TRACE 和 CONNECT 5 种请求方式。常见的有 GET、POST、PUT、DELETE 等。本节内容重点掌握 GET 请求和 POST 请求,其他请求方式这里暂不做介绍。

GET 请求的请求参数拼接在 URL 地址中,请求参数是可见的,因为地址栏数据大小一般限制为 4kB,所以 GET 请求数据大小受限,且只能携带纯文本。由于在请求首行中已经携带请求参数,故无须请求体,也没有请求空行,因此 GET 请求的封装和解析都很快、效率较高。浏览器默认提交的请求均为 GET 请求。

POST 请求参数在地址栏是不可见的相对安全,请求体数据大小也没有限制,可以用来上传任意内容,例如文件、文本等,且上传文件只能使用 POST 请求来实现。与 GET 请求相比,最大的区别是有请求体,数据在请求体中携带,也因此效率较低。

GET 和 POST 请求的区别如表 6-1 所示。

表 6-1 GET 和 POST 请求的区别

GET 请求POST 请求
请求参数位置拼接在地址栏请求体内
数据量的大小有限,地址栏数据大小一般限制为 4kB理论上是无限的
数据安全不安全,地址栏可见相对安全,打开开发者工具(按 F12 键)查看请求体可见
请求体没有请求体有请求体

一般情况下,单击超链接或者在网页地址栏直接输入 URL 地址访问服务器端时,默认请求方式均为 GET 请求,而 Form 表单提交可以借助 GET 请求,也可以借助 POST 请求,关键在于 method 属性值。如果 method 值为 get,则表单提交的请求方式为 GET 请求;如果 method 值为 post,则表单提交的请求方式为 POST 请求。

下面通过具体案例来分别演示 GET 请求和 POST 请求。

1. GET 请求

首先在 JavaWeb 工程下创建 chapter06_http 项目,并复制一份 chapter05_tomcat 项目代码到 chapter06_http 项目下,接下来在第 5 章代码的基础上开展第 6 章的内容。

修改 admin.html 文件,通过创建一个超链接和一个表单来演示 GET 请求,示例代码如下。

运行代码,按 F12 键或打开浏览器开发者工具,选择 “Network” 选项,重新刷新页面后单击该页面 admin.html,选择查看 “Headers” 信息,如图 6-5 所示。

使用不同浏览器查看 F12 页面时,显示形式可能有所不同,图 6-5 是通过谷歌浏览器查看的结果。如图 6-6 所示,在 Edge 浏览器中按 F12 键查看请求和响应信息,导航栏均翻译为中文形式。

77b4a7dcd66ddc58a02f826510fd30a627802af368b833fda4717b722286a474.jpg

a5c607e498d48852428054d47a82f326d4eaafb83f4b0d23fca3955247ed4f98.jpg

下面分别对 GET 请求的各部分展开介绍。请求行的示例代码如下。

从上述代码中可以看出,请求方式为 GET 请求;访问的服务器中的资源路径为 “/chapter06_http/login_success.html”;其中,该请求包含两个请求参数 username 和 password,其值分别为 admin 和 123213;遵循的协议的版本为 HTTP1.1。

请求头(HTTP 请求中的 Headers)的示例代码如下。

从上述代码中可以看出,请求头均以 key-value 键值对组成,下面对其内容一一分析。

2. POST 请求

POST 请求要求将 Form 标签的 method 属性设置为 post,示例代码如下。

运行代码,按 F12 键或打开浏览器开发者工具,选择 “Network” 选项,重新刷新页面后单击该页面 admin.html,选择查看 “Headers” 信息,如图 6-7 所示。

cce1b183400be4f1965b2605e567d80ed5c3be6513d1c894215820afe1f2fcb7.jpg

下面分别对 POST 请求各个部分展开介绍。请求行的示例代码如下。

从上述代码中可以看出,请求方式为 POST 请求;访问服务器端的资源路径 “/chapter06_http/login_success.html”,且路径中不包括请求参数的内容,请求参数保存在请求体中;遵循协议的版本为 HTTP1.1。

请求头的示例代码如下。

有些内容在 GET 请求中的请求头已经介绍过,这里不再重复。Content-Length 表示请求体内容的长度。Cache-Control 值为 “max-age=0”,表示无缓存。Content-Type 表示请求体的内容类型,服务器端会根据该类型解析请求体参数。

请求体即浏览器提交给服务器端的内容,示例代码如下。

该请求体包含了两个参数:username 和 password,对应 GET 请求中 URL 中的参数,由此再次验证了 GET 请求的请求参数直接拼接在 URL 中,而 POST 请求的请求参数存放在请求体中。

6.2.2 响应报文

响应报文同样包括四部分,分别为响应首行(Status Line)、响应头(Headers)、空行(Blank Line)、响应体(Response Body),如图 6-8 所示。

0b45a9f589abf8a264e0aef56d5a45beef2de539873f77eabf915d6bafdda0d6.jpg

响应报文格式如下。

version、headers 和 entity-body 在请求报文中已经做过解释,这里不再重复。

响应行的示例代码如下。

从上述代码中可以看出,响应协议为 HTTP1.1,响应状态码为 200,表示请求成功。

响应头的示例代码如下。

下面对其内容进行分析,具体如下。

响应体即需要浏览器解析使用的内容。如果响应的是 HTML 页面,最终响应体内容会被浏览器显示到页面中,示例代码如下。

6.2.3 响应状态码

提到响应报文不得不介绍一下响应状态码,响应状态码对浏览器来说很重要,通过它可以对服务器端响应给浏览器的结果一目了然。比较有代表性的响应码如下。

响应状态码分为很多种,一般以开头第一位数字作为区分,下面将对其详细介绍。

“1xx” 形式的响应状态码,表示临时响应并需要请求者继续执行操作的状态代码,如表 6-2 所示。

404

海面雾气太大 受天气影响,该页无法正常显示 你可以提供首页。

793743fd29492148f9513709d36dd80419da1518f08881ddf6f004737eb0f5be.jpg

fae72fba32d5f88825c2c5babde5ca32c41380b14e725c5b1c1ceb9c87f11955.jpg

表 6-2 “1xx” 形式的响应状态码

响应状态码说明
100(继续)请求者应当继续提出请求。服务器端返回此代码,表示已收到请求的第一部分,正在等待其余部分
101(切换协议)请求者已要求服务器端切换协议,服务器端已确认并准备切换

“2xx” 形式的响应状态码,表示成功处理了请求的状态代码,如表 6-3 所示。

表 6-3 “2xx” 形式的响应状态码

响应状态码说明
200(成功)服务器端已成功处理了请求。通常,这表示服务器端提供了请求的网页
201(已创建)请求成功并且服务器端创建了新的资源
202(已接受)服务器端已接受请求,但尚未处理
203(非授权信息)服务器端已成功处理了请求,但返回的信息可能来自另一来源
204(无内容)服务器端成功处理了请求,但没有返回任何内容
205(重置内容)重复内容。服务器处理成功,用户终端(如浏览器)应重复文档视图。可通过此返回码清除浏览器的表单域
206(部分内容)服务器端成功处理了部分GET请求

“3xx” 形式的响应状态码,表示要完成请求,需要进一步操作。通常情况下,这些状态代码用来重定向,如 6-4 表所示。

表 6-4 “3xx” 形式的响应状态码

响应状态码说明
300(多种选择)针对请求,服务器端可执行多种操作。服务器端可根据请求者(user agent)选择一项操作,或提供操作列表供请求者选择
301(永久移动)请求的网页已永久移动到新位置。服务器端返回此响应(对GET或HEAD请求的响应)时,会自动将请求者转到新位置
302(临时移动)临时移动。与301类似,但资源只是临时被移动。客户端应继续使用原URI
303(查看其他位置)请求者应当对不同的位置使用单独的GET请求来检索响应时,服务器端返回此代码
304(未修改)自从上次请求后,请求的网页未被修改过。服务器端返回此响应时,不会返回网页内容
305(使用代理)请求者只能使用代理访问请求的网页。如果服务器端返回此响应,那么表示请求者应使用代理
307(临时重定向)临时重定向。与302类似,使用GET请求重定向

“4xx” 形式的响应状态码,表示请求可能出错,妨碍了服务器端的处理,如表 6-5 所示。

表 6-5 “4xx” 形式的响应状态码

响应状态码说明
400(错误请求)服务器端不理解请求的语法
401(未授权)请求要求身份验证。对于需要登录的网页,服务器端可能返回此响应
403(禁止)服务器端拒绝请求
404(未找到)服务器端找不到请求的网页
405(方法禁用)禁用请求中指定的方法
406(不接受)无法使用请求的内容特性响应请求的网页
407(需要代理授权)此状态代码与401(未授权)类似,但指定请求者应当授权使用代理
408(请求超时)服务器端等候请求时发生超时
409(冲突)服务器端在完成请求时发生冲突。服务器端必须在响应中包含有关冲突的信息
410(已删除)如果请求的资源已被永久删除,服务器端就会返回此响应
411(需要有效长度)服务器端不接受不含有效内容长度标头字段的请求
412(未满足前提条件)服务器端未满足请求者在请求中设置的其中一个前提条件
413(请求实体过大)服务器端无法处理请求,因为请求实体过大,超出服务器端的处理能力
414(请求的URI过长)请求的URI(通常为网址)过长,服务器端无法处理
415(不支持的媒体类型)请求的格式不受请求页面的支持
416(请求范围不符合要求)如果页面无法提供请求的范围,则服务器端会返回此状态代码
417(未满足期望值)服务器端未满足“期望”请求标头字段的要求

“5xx” 形式的响应状态码,表示服务器端在尝试处理请求时发生内部错误。值得注意的是,这些错误可能是服务器端本身的错误,而不是请求出错,如表 6-6 所示。

表 6-6 “5xx” 形式的响应状态码

响应状态码说明
500(服务器端内部错误)服务器端遇到错误,无法完成请求
501(尚未实施)服务器端不具备完成请求的功能。例如,服务器端无法识别请求方法时,可能会返回此代码
502(错误网关)服务器端作为网关或代理,从上游服务器端收到无效响应
503(服务不可用)服务器端目前无法使用(由于超载或停机维护),但是通常情况下,这只是暂时状态
504(网关超时)服务器端作为网关或代理,但是没有及时从上游服务器端收到请求
505(HTTP 版本不受支持)服务器端不支持请求中所使用的 HTTP 版本

6.3 本章小结

本章主要介绍了 HTTP 相关的知识,包括 HTTP 的会话方式、不同版本间的区别,以及报文的概念。作为 JavaWeb 前置知识,希望读者对 HTTP 基础知识能够有一个大致的了解。需要重点掌握报文内容,能够理解请求报文和响应报文中传递的信息,当代码报错时,能够通过响应状态码快速解决问题。