计算机网络 - HTTP 与 HTTPS 协议

警告
本文最后更新于 2020-07-09,文中内容可能已过时。

HTTP 和 HTTPS 是最常用的两个协议,本篇对它们进行介绍。

HTTP 全称为超文本传输协议(HyperText Transfer Protocol),它定义了浏览器(客户端进程)如何向网络上的服务器请求网络文档,以及服务器如何将文档传送给浏览器。从层次角度看,HTTP 是一个应用层协议,使用网络层的 TCP 进行可靠传输。

一个大致的工作过程如下所述。每个网络节点都有一个服务器进程,它在后台不间断地监听着 TCP 的 80 端口,以便发现是否有来自浏览器的连接建立请求。一旦监听到连接请求并遵照握手协议建立 TCP 连接后,浏览器就会向该服务器发出浏览某个页面的请求,服务器就返回对应的页面作为响应。最后,TCP 连接被释放掉。

HTTP 就是浏览器和服务器之间请求和响应的交互需要遵循的格式与规则。它规定浏览器与服务器的交互是一个 ASCII 码串,这段字符串的格式就是 HTTP 报文格式。因为 HTTP 是建立在 TCP 上的协议,因此这段字符串也是 TCP 报文的数据部分。

无论是用户主动在浏览器地址栏输入了某个 URL,还是在页面上点击了某个元素,在背后都会转化为一个链接,然后浏览器就会在网络上找到链接对应的页面。假设我输入的 URL 或点击的元素指向了「清华大学院系设置」页面,具体的链接为 http://www.tsinghua.edu.cn/chn/yxsz/index.htm,之后发生的事情如下所述:

  1. 浏览器向 DNS 请求解析 www.tsinghua.edu.cn 的 IP 地址;
  2. 域名系统返回清华大学服务器的地址 166.111.4.100;
  3. 浏览器与服务器建立 TCP 连接;
  4. 浏览器发出取文件命令:GET /chn/yxsz/index.htm;
  5. 服务器给出响应,把文件 index.htm 发给浏览器;
  6. 释放 TCP 连接;
  7. 浏览器渲染并显示 index.htm 文件,显示的页面就是「清华大学院系设置」页面

数据的可靠性由底层的 TCP 保证,HTTP 本身是无连接的。从上面的过程也可以看出,通信双方并不需要建立和释放 HTTP 连接。同时 HTTP 也是无状态的,无状态的含义是,如果此时浏览器再次访问「清华大学院系设置」页面,服务器会执行一遍重复的过程,再返回一次 index.htm 页面,因为服务器不记得这个浏览器曾经访问过。这种无状态特性既有好处也有坏处,我们以后会介绍这部分内容。

HTTP 有两类报文:

  1. 请求报文 — 从客户向服务器发送请求报文;
  2. 响应报文 — 服务器向客户返回响应;

上一小节已经提到过,HTTP 是面向文本的,本质上是一串 ASCII 码字符串,报文的格式就是对字符串的各部分含义进行规定,各部分长度也是不固定的。

HTTP请求与响应报文

HTTP 请求与响应报文都是由三个部分组成:开始行、首部行和实体主体。

  • 实体主体就是数据部分,请求报文一般都不用,响应报文中也可能没有这个字段。
  • 首部行不一定是一行,可能有多行,也可能没有,每行都是「键:值」形式,其中键叫做首部字段名,每一行结束都要跟一个回车和换行。整个首部行部分结束,还要加一个空行和实体主体分开。首部行的作用是说明浏览器、服务器或报文主体的一些基本信息,首部字段名大都是规定好的。
  • 开始行是请求和响应报文唯一不同的地方。请求报文的开始行可以叫做请求行,响应报文的开始行叫做状态行,开始行的三个部分都以空格分开,末尾要添加 回车 + 换行 与首部行部分区分。

请求报文的第一行请求行包括三部分:方法、URI 和版本。

方法是浏览器希望执行的操作,其实就是一些命令,比如提到的 GET,请求报文的类型一般根据方法的类型进行区分,到 HTTP 1.1 共有 9 种方法,如下:

方法意义
OPTION 请求一些选项的信息
GET 请求指定的页面信息,并返回实体主体
HEAD 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和 / 或已有资源的修改
PUT 从客户端向服务器传送的数据取代指定的文档的内容
DELETE 请求服务器删除指定的页面
TRACE 回显服务器收到的请求,主要用于测试或诊断
CONNECTHTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器
PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新

通常,最容易混淆使用的是 PUT 和 POST 两个方法,这里进行说明

PUT 和 POST 在使用效果上的区别在于幂等性,幂等性是指,如果一个方法执行多次,产生的效果是一样的,这里 PUT 方法是幂等的,更通俗的解释为

  • PUT:如果两个请求相同,后一个请求会把前一个请求覆盖掉;
  • POST:后一个请求不会把前一个请求覆盖掉

更多的看 RFC:https://tools.ietf.org/html/rfc7231#section-4.3

URI 是请求资源的 URI,版本是指 HTTP 协议的版本,现在一般是 HTTP/1.1。以前面 1.1 小节提到的例子来说明,请求「清华大学院系设置」页面,其 HTTP 请求报文的开始行应当是

1
GET http://www.tsinghua.edu.cn/chn/yxsz/index.htm HTTP/1.1

这里给出一个完整的请求报文的例子,注意这里请求行使用相对 URL ,这是因为首部行给出了主机域名。

1
2
3
4
5
6
GET /chn/yxsz/index.htm HTTP/1.1
Host: www.tsinghua.edu.cn  // 主机域名
Connection: close  // 告诉服务器发送完请求的文档后就可以释放连接
User-Agent: Mozilla/5.0  // 表明用户代理是使用 Netscape 浏览器
Accept-Language: cn  // 表示用户希望优先得到中文版本的文档
// 这里有一个空行,后面的实体主体部分为空

响应报文的状态行同样分三部分:版本,状态码和短语。

版本依然是 HTTP 协议版本,状态码用来说明不同的响应情况,短语是对状态码的简单说明。状态行的示例如下

1
HTTP/1.1 202 Accepted

HTTP 状态码 (tatus Code) 都是三位数字,分为 5 大类共 33 种(见 RFC 2616),大类的含义如下表。关于更具体地状态码信息,见 附录 1。

分类分类描述
1** 信息,服务器收到请求,需要请求者继续执行操作
2** 成功,操作被成功接收并处理
3** 重定向,需要进一步的操作以完成请求
4** 客户端错误,请求包含语法错误或无法完成请求
5** 服务器错误,服务器在处理请求的过程中发生了错误

继续举例,假设请求的网页从 http://www.ee.xyz.edu/index.html 转移到了一个新的地址,则响应报文的状态行和一个首部行就是下面的形式:

1
2
HTTP/1.1 301 Moved Permanently
Location: http://www.xyz.edu/ee/index.html

首部行地键值定义很多都有固定的含义,可以参考附录 2。

HTTP 从诞生到现在一共 4 个版本,第一个版本 HTTP/0.9 诞生于 1991 年,目前已过时,剩下的三个协议比较如下表

HTTP1.0HTTP1.1HTTP2.0
诞生时间 1992-19961997-19992012-2014
Host 头
Range 头
长连接
request methodGET HEAD POST 以上 + OPTIONS PUT DELETE TRACE CONNECT 以上全部
cacheExpire Last-Modefied Pragma 以上 + ETag Cache-Control 以上全部
header 压缩
多路复用
服务器推送

目前多数都已经切换到了 HTTP/1.1,但由于现在的网页元素越来越丰富(文字、图片、视频等等),使用 HTTP/2.0 会有更低的延迟和更快的加载效果。

HTTPS 全称为安全超文本传输协议(Secure Hypertext Transfer Protocol),主要是为了解决身份认证和 HTTP 明文传输的问题。

本质上,HTTPS 是在 HTTP 的基础上添加了 SSL/TLS 协议,因此接下来我们先介绍 SSL/TLS 协议。

SSL 全称为安全套接字层(Secure Socket Layer),是网景公司在 1994 年开发的安全协议,是一个运输层协议(实际上是位于运输层和应用层之间)。1995 年 SSL 就被转交给了 IETF(互联网工程任务组),开始进行标准化。IETF 在 SSL 3.0 的基础上设计了 TLS 协议,现在使用的基本都是 2008 年发布的 TLS 1.2,不过在 2018 年已经发布了最新的 TLS 1.3。F12 打开浏览器控制台,在安全选项卡可以看到当前网页使用的 TLS 版本。至此我们知道,SSL 和 TLS 不是两个协议,而是一个协议的不同阶段。

SSL/TLS 协议主要是解决 HTTP 身份认证和明文传输问题,以网上购物为例,假如购物网站使用 HTTP 协议,那么可能出现如下问题

  1. 浏览器无法确认访问的服务器确实是销售商的,销售商也无法对客户进行鉴别;
  2. 顾客的浏览器和销售商的服务器间进行数据交互(比如账单传输)是明文的,可以被别人抓取查看甚至更改。

SSL/TLS 通过证书机制进行身份鉴别,通过协商一个对称会话密钥来进行安全的数据传输。下面通过 HTTPS 的通信过程进行详细解释。

一个比较清晰的流程说明图片如下

第一部分是证书验证过程,服务端的公司需要首先向专门的数字证书认证机构申请数字证书,获得证书的同时会得到一对公私钥,私钥自己保存,公钥放在证书里。另外,证书里除了公钥外,还包含证书颁发机构信息、公司信息和证书有效期等字段。客户端通过 HTTPS 协议进行请求时,服务器就会把证书传给客户端。注意,证书颁发机构颁发证书时,已经用自己的私钥进行了签名,公钥公开在网络中,所以客户端收到证书后,就可以利用网络中的证书颁发机构的公钥来验证证书的合法性,这就是验证服务端身份的过程。我们点击浏览器搜索栏的锁图标,可以查看网站证书,下面是 B 站的证书。

接下来是协商会话密钥的过程,协商好的对称会话密钥会用于之后的通信进行数据加解密。之前我们提到,客户端收到的证书里包含一份公钥,客户端验证了服务端的合法性后,就会将证书里的公钥提取出来,同时自己生成一串随机数,然后利用该公钥对随机数进行加密,这串随机数就是之后的会话密钥。客户端将加密的随机数发回给服务器,服务器利用自己保存的私钥进行解密,就可以得到该随机数,此时,会话密钥的协商就完成了。

最后,服务器和客户端之间会利用协商好的密钥进行一次数据传输进行验证。服务器使用密钥(随机数)对数据进行加密并发送给客户端,客户端同样使用该随机数进行解密,自此通信完成。

这是一个大致的过程,实际的请求与响应如下,这里借用了《图解 HTTP》的图,还要注意的一点是,TLS 的通信过程是在建立 TCP 连接后开始的。

  1. 客户端发送 Client Hello 报文,开始 SSL 通信,报文中包含客户端使用的 TLS 协议版本,加密组件列表(支持的加密算法和密钥长度);
  2. 服务器以 Server Hello 报文作为应答,同样包含 TLS 协议版本,并从客户端发来的加密组件中选定一种,放在报文中发回去;
  3. 服务器发送 Certificate 报文,报文包含数字证书;
  4. 服务器发送 Server Hello Done 报文,表明初始的协商结束;
  5. 客户端验证证书合法性,利用证书中的公钥对随机数进行加密,然后放在 Client Key Exchange 报文中发回去;
  6. 客户端发送 Change Cipher Spec 报文,提示服务端之后以协商好的会话密钥通信;
  7. 客户端发送 Finished 报文,将包含连接至今所有的报文的加密值,如果之后服务端能成功解析才能说明成功;
  8. 服务端同样发送 Change Ciphper Spec 报文,表明之后用协商好的会话密钥通信;
  9. 服务端发送 Finished 报文;
  10. 客户端和服务端的 Finished 报文交换完毕后,实际上 TLS 连接就算建立完成了,之后的所有通信都使用会话密钥加密;
  11. 最后关闭连接时,客户端发送 close_notify 报文断开 TLS;
  12. TLS 关闭后才会完成四次握手关闭 TCP 连接。

大家最常问的一个问题还是 HTTP 和 HTTPS 的区别,这里做一下总结

  1. HTTP 使用 80 端口,HTTPS 使用 443 端口;
  2. HTTPS 可以保证身份合法以及数据传输的安全;
  3. HTTPS 建立连接的过程比 HTTP 复杂很多;
  4. HTTPS 通信更慢,因为要进行数据的加解密;

实际上,不是所有的信息都使用 HTTPS,一是因为加解密对资源的消耗比较大,普通的非敏感信息不需要加密传输,另一方面是 HTTPS 证书价格太贵。

状态码状态码英文名称中文描述
100Continue 继续。客户端应继续其请求
101Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到 HTTP 的新版本协议
200OK 请求成功。一般用于 GET 与 POST 请求
201Created 已创建。成功请求并创建了新的资源
202Accepted 已接受。已经接受请求,但未处理完成
203Non-Authoritative Information 非授权信息。请求成功。但返回的 meta 信息不在原始的服务器,而是一个副本
204No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206Partial Content 部分内容。服务器成功处理了部分 GET 请求
300Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301Moved Permanently 永久移动。请求的资源已被永久的移动到新 URI,返回信息会包括新的 URI,浏览器会自动定向到新 URI。今后任何新的请求都应使用新的 URI 代替
302Found 临时移动。与 301 类似。但资源只是临时被移动。客户端应继续使用原有 URI
303See Other 查看其它地址。与 301 类似。使用 GET 和 POST 请求查看
304Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305Use Proxy 使用代理。所请求的资源必须通过代理访问
306Unused 已经被废弃的 HTTP 状态码
307Temporary Redirect 临时重定向。与 302 类似。使用 GET 请求重定向
308Permanent Redirect 永久重定向
400Bad Request 客户端请求的语法错误,服务器无法理解
401Unauthorized 请求要求用户的身份认证
402Payment Required 保留,将来使用
403Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置 "您所请求的资源无法找到" 的个性页面
405Method Not Allowed 客户端请求中的方法被禁止
406Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407Proxy Authentication Required 请求要求代理的身份认证,与 401 类似,但请求者应当使用代理进行授权
408Request Time-out 服务器等待客户端发送的请求时间过长,超时
409Conflict 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突
410Gone 客户端请求的资源已经不存在。410 不同于 404,如果资源以前有现在被永久删除了可使用 410 代码,网站设计人员可通过 301 代码指定资源的新位置
411Length Required 服务器无法处理客户端发送的不带 Content-Length 的请求信息
412Precondition Failed 客户端请求信息的先决条件错误
413Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个 Retry-After 的响应信息
414Request-URI Too Large 请求的 URI 过长(URI 通常为网址),服务器无法处理
415Unsupported Media Type 服务器无法处理请求附带的媒体格式
416Requested range not satisfiable 客户端请求的范围无效
417Expectation Failed 服务器无法满足 Expect 的请求头信息
500Internal Server Error 服务器内部错误,无法完成请求
501Not Implemented 服务器不支持请求的功能,无法完成请求
502Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的 Retry-After 头信息中
504Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505HTTP Version not supported 服务器不支持请求的 HTTP 协议的版本,无法完成处理
应答头说明
Allow 服务器支持哪些请求方法(如 GET、POST 等)。
Content-Encoding 文档的编码(Encode)方法。只有在解码之后才可以得到 Content-Type 头指定的内容类型。利用 gzip 压缩文档能够显著地减少 HTML 文档的下载时间。Java 的 GZIPOutputStream 可以很方便地进行 gzip 压缩,但只有 Unix 上的 Netscape 和 Windows 上的 IE 4、IE 5 才支持它。因此,Servlet 应该通过查看 Accept-Encoding 头(即 request.getHeader (“Accept-Encoding”))检查浏览器是否支持 gzip,为支持 gzip 的浏览器返回经 gzip 压缩的 HTML 页面,为其他浏览器返回普通页面。
Content-Length 表示内容长度。只有当浏览器使用持久 HTTP 连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入 Content-Length 头,最后通过 byteArrayStream.writeTo (response.getOutputStream () 发送内容。
Content-Type 表示后面的文档属于什么 MIME 类型。Servlet 默认为 text/plain,但通常需要显式地指定为 text/html。由于经常要设置 Content-Type,因此 HttpServletResponse 提供了一个专用的方法 setContentType。
Date 当前的 GMT 时间。你可以用 setDateHeader 来设置这个头以避免转换时间格式的麻烦。
Expires 应该在什么时候认为文档已经过期,从而不再缓存它?
Last-Modified 文档的最后改动时间。客户可以通过 If-Modified-Since 请求头提供一个日期,该请求将被视为一个条件 GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个 304(Not Modified)状态。Last-Modified 也可用 setDateHeader 方法来设置。
Location 表示客户应当到哪里去提取文档。Location 通常不是直接设置的,而是通过 HttpServletResponse 的 sendRedirect 方法,该方法同时设置状态代码为 302。
Refresh 表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过 setHeader (“Refresh”, “5; URL=http://host/path”) 让浏览器读取指定的页面。 注意这种功能通常是通过设置 HTML 页面 HEAD 区的<META HTTP-EQUIV=“Refresh” CONTENT=“5;URL=http://host/path">实现,这是因为,自动刷新或重定向对于那些不能使用 CGI 或 Servlet 的 HTML 编写者十分重要。但是,对于 Servlet 来说,直接设置 Refresh 头更加方便。 注意 Refresh 的意义是"N 秒之后刷新本页面或访问指定页面”,而不是 "每隔 N 秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个 Refresh 头,而发送 204 状态代码则可以阻止浏览器继续刷新,不管是使用 Refresh 头还是<META HTTP-EQUIV=“Refresh” …>。 注意 Refresh 头不属于 HTTP 1.1 正式规范的一部分,而是一个扩展,但 Netscape 和 IE 都支持它。
Server 服务器名字。Servlet 一般不设置这个值,而是由 Web 服务器自己设置。
Set-Cookie 设置和页面关联的 Cookie。Servlet 不应使用 response.setHeader (“Set-Cookie”, …),而是应使用 HttpServletResponse 提供的专用方法 addCookie。参见下文有关 Cookie 设置的讨论。
WWW-Authenticate 客户应该在 Authorization 头中提供什么类型的授权信息?在包含 401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader (“WWW-Authenticate”, “BASIC realm=\“executives\”")。 注意 Servlet 一般不进行这方面的处理,而是让 Web 服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。
支付宝
微信
0%