HTTP实用指北 | 青训营笔记

158 阅读15分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 4 天

一 、基础概念

HTTP协议的主要特点

  • 简单快速
  • 灵活
  • 无连接
  • 无状态

通常我们要答出以上四个内容。如果实在记不住,一定要记得后面的两个:无连接、无状态

我们分别来解释一下。

简单快速

简单:每个资源(比如图片、页面)都通过 url 来定位。这都是固定的,在http协议中,处理起来也比较简单,想访问什么资源,直接输入url即可。

灵活

http协议的头部有一个数据类型,通过http协议,就可以完成不同数据类型的传输。

无连接

连接一次,就会断开,不会继续保持连接。

无状态

客户端和服务器端是两种身份。第一次请求结束后,就断开了,第二次请求时,服务器端并没有记住之前的状态,也就是说,服务器端无法区分客户端是否为同一个人、同一个身份。

有的时候,我们访问网站时,网站能记住我们的账号,这个是通过其他的手段(比如 session)做到的,并不是http协议能做到的。

HTTP报文的组成部分

请求和响应报文

客户端发送一个请求报文给服务器,服务器根据请求报文中的信息进行处理,并将处理结果放入响应报文中返回给客户端。

请求报文结构:

  • 第一行是包含了请求方法、URL、协议版本;
  • 接下来的多行都是请求首部 Header,每个首部都有一个首部名称,以及对应的值。
  • 一个空行用来分隔首部和内容主体 Body
  • 最后是请求的内容主体
GET http://www.example.com/ HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Host: www.example.com
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
If-None-Match: "3147526947+gzip"
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 xxx

param1=1&param2=2

响应报文结构:

  • 第一行包含协议版本、状态码以及描述,最常见的是 200 OK 表示请求成功了
  • 接下来多行也是首部内容
  • 一个空行分隔首部和内容主体
  • 最后是响应的内容主体
HTTP/1.1 200 OK
Age: 529651
Cache-Control: max-age=604800
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 648
Content-Type: text/html; charset=UTF-8
Date: Mon, 02 Nov 2020 17:53:39 GMT
Etag: "3147526947+ident+gzip"
Expires: Mon, 09 Nov 2020 17:53:39 GMT
Keep-Alive: timeout=4
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Proxy-Connection: keep-alive
Server: ECS (sjc/16DF)
Vary: Accept-Encoding
X-Cache: HIT

<!doctype html>
<html>
<head>
    <title>Example Domain</title>
	// 省略... 
</body>
</html>

HTTP方法

包括:

  • GET:获取资源
  • POST:传输资源
  • put:更新资源
  • DELETE:删除资源
  • HEAD:获得报文首部

HTTP方法有很多,但是上面这五个方法,要求在面试时全部说出来,不要漏掉。

get 和 post 比较常见。

put 和 delete 在实际应用中用的很少。况且,业务中,一般不删除服务器端的资源。

head 可能偶尔用的到。

get 和 post的区别

post与gets的区别.png 有一点要强调,get是相对不隐私的,而post是相对隐私的

我们大概要记住以下几点:

1、浏览器在回退时,get不会重新请求,但是post会重新请求。【重要】

2、get请求会被浏览器主动缓存,而post不会。【重要】

3、get请求的参数,会报保留在浏览器的历史记录里,而post不会。做业务时要注意。为了防止CSRF攻击,很多公司把get统一改成了post。

4、get请求在url中传递的参数有大小限制,基本是2kb,不同的浏览器略有不同。而post没有注意。

5、get的参数是直接暴露在url上的,相对不安全。而post是放在请求体中的。

http状态码

http状态码分类: http状态码分类.png

常见的http状态码: 常见的http状态码.png 部分解释:

  • 206的应用:range指的是请求的范围,客户端只请求某个大文件里的一部分内容。比如说,如果播放视频地址或音频地址的前面一部分,可以用到206。
  • 301:重定向(永久)。
  • 302:重定向(临时)。
  • 304:我这个服务器告诉客户端,你已经有缓存了,不需要从我这里取了。 常见的http状态码2.png 400和401用的不多。403指的是请求被拒绝。404指的是资源不存在。

URL

概述

URL 是“统一资源定位符”(Uniform Resource Locator)的首字母缩写,中文译为“网址”,表示各种资源的互联网地址。下面就是一个典型的 URL。

https://www.example.com/path/index.html

所谓资源,可以简单理解成各种可以通过互联网访问的文件,比如网页、图像、音频、视频、JavaScript 脚本等等。只有知道了它们的 URL,才能在互联网上获取它们。

只要资源可以通过互联网访问,它就必然有对应的 URL。一个 URL 对应一个资源,但是同一个资源可能对应多个 URL。

URL 是互联网的基础。互联网之所以“互联”,就是因为网页可以通过“链接”(link),包含其他 URL。用户只要点击,就可以从一个 URL 跳转到另一个 URL,前往不同的网站。

网址的组成部分

URL 由多个部分组成。下面是一个比较复杂的 URL,实际的 URL 通常不会有这么多部分。

https://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#anchor

我们看看,这个 URL 的各个部分。

协议

协议(scheme)是浏览器请求服务器资源的方法,上例是https://的部分,表示使用 HTTPS 协议。

互联网支持多种协议,必须指明网址使用哪一种协议,默认是 HTTP 协议。也就是说,如果省略协议,直接在浏览器地址栏输入www.example.com,那么浏览器默认会访问http://www.example.com。HTTPS 是 HTTP 的加密版本,出于安全考虑,越来越多的网站使用这个协议。

HTTP 和 HTTPS 的协议名称后面,紧跟着一个冒号和两个斜杠(://)。其他协议不一定如此,邮件地址协议mailto:的协议名后面只有一个冒号,比如mailto:foo@example.com

主机

主机(host)是资源所在的网站名或服务器的名字,又称为域名。上例的主机是www.example.com

有些主机没有域名,只有 IP 地址,比如192.168.2.15。这种情况常常出现在局域网。

端口

同一个域名下面可能同时包含多个网站,它们之间通过端口(port)区分。“端口”就是一个整数,可以简单理解成,访问者告诉服务器,想要访问哪一个网站。HTTP 协议的默认端口是80,如果省略了这个参数,服务器就会返回80端口的网站。

端口紧跟在域名后面,两者之间使用冒号分隔,比如www.example.com:80

路径

路径(path)是资源在网站的位置。比如,/path/index.html这个路径,指向网站的/path子目录下面的网页文件index.html

互联网的早期,路径是真实存在的物理位置。现在由于服务器可以模拟这些位置,所以路径只是虚拟位置。

路径可能只包含目录,不包含文件名,比如/foo/,甚至结尾的斜杠都可以省略。这时,服务器通常会默认跳转到该目录里面的index.html文件(即等同于请求/foo/index.html),但也可能有其他的处理(比如列出目录里面的所有文件),这取决于服务器的设置。一般来说,访问www.example.com这个网址,很可能返回的是网页文件www.example.com/index.html

查询参数

查询参数(parameter)是提供给服务器的额外信息。参数的位置是在路径后面,两者之间使用?分隔,上例是?key1=value1&key2=value2

查询参数可以有一组或多组。每组参数都是键值对(key-value pair)的形式,同时具有键名(key)和键值(value),它们之间使用等号(=)连接。比如,key1=value就是一个键值对,key1是键名,value1是键值。

多组参数之间使用&连接,比如key1=value1&key2=value2

锚点

锚点(anchor)是网页内部的定位点,使用#加上锚点名称,放在网址的最后,比如#anchor。浏览器加载页面以后,会自动滚动到锚点所在的位置。

锚点名称通过网页元素的id属性命名,详见《元素的属性》一章。

URL 字符

URL 的各个组成部分,只能使用以下这些字符。

  • 26个英语字母(包括大写和小写)
  • 10个阿拉伯数字
  • 连词号(-
  • 句点(.
  • 下划线(_

此外,还有18个字符属于 URL 的保留字符,只能在给定的位置出现。比如,查询参数的开头是问号(?),也就是说,问号只能出现查询参数的开头,出现在其他位置就是非法的,会导致网址解析错误。网址的其他部分如果要使用这些保留字符,必须使用它们的转义形式。

URL 字符转义的方法是,在这些字符的十六进制 ASCII 码前面加上百分号(%)。下面是这18个字符及其转义形式。

  • !:%21
  • #:%23
  • $:%24
  • &:%26
  • ':%27
  • (:%28
  • ):%29
  • *:%2A
  • +:%2B
  • ,:%2C
  • /:%2F
  • ::%3A
  • ;:%3B
  • =:%3D
  • ?:%3F
  • @:%40
  • [:%5B
  • ]:%5D

举例来说,有一个网页的 URL 是foo?bar.html,即文件里面包含一个问号,那么需要写成foo%3Fbar.html

URL 的合法字符,其实也可以采用这种转义方法,但是不建议使用。比如,字母a的十六进制 ASCII 码是61,转义形式后就是%61。因此,www.apple.com又可以写成www.%61pple.com,浏览器一样识别。

值得注意的是,空格的转义形式是%20。对于那些包含空格的文件名,这个转义是必须的。

既不属于合法字符、也不属于保留字符的其他字符(比如汉字),理论上不需要手动转义,可以直接写在 URL 里面,比如www.example.com/中国.html,浏览器会自动将它们转义,发给服务器。转义方法是使用这些字符的十六进制 UTF-8 编码,每两位算作一组,然后每组头部添加百分号(%)。

举例来说,汉字的 UTF-8 十六进制编码是e4b8ad,每两个字符一组,URL 转义后就为%e4%b8%ad。也就是说,URL 里面凡是有汉字的地方,都要写成%e4%b8%ad。因此,访问www.example.com/中国.html这个网址,需要写成下面的样子。

www.example.com/%e4%b8%ad%e5%9b%bd.html

上面代码中,的转义形式是%e4%b8%ad%e5%9b%bd

绝对 URL 和相对 URL

URL 分成两种:绝对 URL 和相对 URL。

绝对 URL 指的是,只靠 URL 本身就能确定资源的位置。这意味着,URL 必须带有资源的完整信息,包含协议、主机、路径等部分。前面的例子都是绝对 URL。

相对 URL 指的是,URL 不包含资源位置的全部信息,必须结合当前网页的位置,才能定位资源。比如,当前网页的 URL 是https://www.example.com/path/index.html,该网页上面有一个资源,URL 指向a.html,这个就是相对 URL。因为只知道a.html,并不能定位资源。浏览器假定,a.html与当前网址在同一个子目录下面,从而得到绝对 URL https://www.example.com/path/a.html

相对 URL 如果以斜杠(/)开头,就表示网站的根目录。否则,必须以当前目录为起点,推算资源的位置。比如,相对 URL /foo/bar.html表示网站根目录的子目录foofoo/bar.html表示在当前目录的foo子目录。

URL 还可以使用两个特殊简写,表示特定位置。

  • .:表示当前目录,比如./a.html(当前目录下的a.html文件)
  • ..:表示上级目录,比如../a.html(上级目录下的a.html文件)

这两种简写可以多个连用,比如../../表示上两级目录。

绝对 URL 也可以使用这两个简写,比如www.example.com/./index.html等同于www.example.com/index.html,这时.相当于根目录的当前目录,即根目录本身。

<base>

<base>标签指定网页内部的所有相对 URL 的计算基准。整张网页只能有一个<base>标签,而且只能放在<head>里面。它是单独使用的标签,没有闭合标签,下面是一个例子。

<head>
<base href="https://www.example.com/files/" target="_blank">
</head>

<base>标签的href属性给出计算的基准网址,target属性给出如何打开链接的说明(参见《链接》一章)。已知计算基准是https://www.example.com/files/,那么相对 URL foo.html,就可以转成绝对 URL https://www.example.com/files/foo.html

注意,<base>标签必须至少具有href属性或target属性之一。

<base href="http://foo.com/app/">
<base target="_blank">

一旦设置了<base>,就对整个网页都有效。如果要改变某个链接的行为,只能用绝对链接替代相对链接。尤其需要注意锚点,这时锚点也是针对<base>计算的,而不是针对当前网页的 URL。

安全性问题

HTTP 有以下安全性问题:

  • 使用明文进行通信,内容可能会被窃听;
  • 不验证通信方的身份,通信方的身份有可能遭遇伪装;
  • 无法证明报文的完整性,报文有可能遭篡改。

HTTPS 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)通信,再由 SSL 和 TCP 通信,也就是说 HTTPS 使用了隧道进行通信。

通过使用 SSL,HTTPS 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。

\

加密

1. 对称密钥加密

对称密钥加密(Symmetric-Key Encryption),加密和解密使用同一密钥。

  • 优点:运算速度快;
  • 缺点:无法安全地将密钥传输给通信方。

2.非对称密钥加密

非对称密钥加密,又称公开密钥加密(Public-Key Encryption),加密和解密使用不同的密钥。

公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。

非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确。

  • 优点:可以更安全地将公开密钥传输给通信发送方;
  • 缺点:运算速度慢。

3. HTTPS 采用的加密方式

上面提到对称密钥加密方式的传输效率更高,但是无法安全地将密钥 Secret Key 传输给通信方。而非对称密钥加密方式可以保证传输的安全性,因此我们可以利用非对称密钥加密方式将 Secret Key 传输给通信方。HTTPS 采用混合的加密机制,正是利用了上面提到的方案:

  • 使用非对称密钥加密方式,传输对称密钥加密方式所需要的 Secret Key,从而保证安全性;
  • 获取到 Secret Key 后,再使用对称密钥加密方式进行通信,从而保证效率。(下图中的 Session Key 就是 Secret Key)

认证

通过使用 证书 来对通信方进行认证。

数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。

服务器的运营人员向 CA 提出公开密钥的申请,CA 在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起。

进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。

完整性保护

SSL 提供报文摘要功能来进行完整性保护。

HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。

HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。

HTTPS 的缺点

  • 因为需要进行加密解密等过程,因此速度会更慢;
  • 需要支付证书授权的高额费用。

相关资源: