HTTP 是什么?有什么特点?
HTTP
- HTTP 是超文本传输协议,它使用 TCP 作为传输层协议,保证了数据传输的可靠性。属于网络层级中的应用层。HTTP 默认端口 80。
HTTP 的特点
- 无状态 就是 HTTP 传输是没有记忆能力,第一次传送的数据如果第二次还要传的话,需要重新传。(这也可以当做http的缺点)
- 无连接 传送完数据之后就断开了连接。
- 灵活可扩展,主要体现在两个方面。一个是语义上的自由,只规定了基本格式,比如空格分隔单词,换行分隔字段,其他的各个部分都没有严格的语法限制。另一个是传输形式的多样性,不仅仅可以传输文本,还能传输图片、视频等任意数据,非常方便
- 可靠传输。HTTP 基于 TCP/IP,因此把这一特性继承了下来。可靠性强。
HTTP连接模式
HTTP 有两种连接模式,一种是持续连接,一种非持续连接。
持续连接
持续连接下,TCP 连接默认不关闭,可以被多个请求复用。采用持续连接的好处是可以避免每次建立 TCP 连接三次握手时所花费的时间。在 HTTP1.0 以前使用的非持续的连接,但是可以在请求时,加上 Connection: keep-alive 来要求服务器不要关闭 TCP 连接。HTTP1.1 以后默认采用的是持续的连接。目前对于同一个域,大多数浏览器支持同时建立6个持久连接。
非持续连接
非持续连接指的是服务器必须为每一个请求的对象建立和维护一个全新的连接。
请求和响应
请求响应的组成
- 请求行、请求头、空行、请求体
- 状态行、响应头、空行、响应体
空行主要用来区分开头部和实体。
如果说在头部中间故意加一个空行会怎么样?
那么空行后的内容全部被视为实体。
请求行 状态行包括什么?
- 请求行有协议版本 请求路径 请求方法
GET /home HTTP/1.1
- 状态行有协议版本 状态码 相应的状态信息(原因)
HTTP/1.1 200 OK
常见的请求头有什么?
Accept 可以接受的数据类型
Accept-Charset 可接受的字符集
Accept-Language 可接受的响应内容语言列表
Accept-Encoding 告诉服务器,客户机支持的数据压缩格式。
Content-Type 请求参数的数据类型
Authorization HTTP授权的授权证书 一般我们用来存放token,例如Authorization: Bearer QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接)
Host 请求服务器的域名及端口号(服务端)
Origin: 请求的来源域名和端口号 (跨域请求时,浏览器会自动带上这个头信息)
Referer: 当前发送请求的域名及端口号及参数,请求资源的完整URI(客户端)https:/localhost:8081/link?query=xxxxx
Remote Address 服务器ip和端口
Referrer-Policy(来源协议)用来规定什么情况下显示Referer字段及refer字段内显示多少信息。
Cookie cookie信息
User-Agent 浏览器的一些信息
Date 客户机通过这个头告诉服务器,客户机当前请求时间
Cache-Control 是否使用缓存 max-age no-cache no-store等等
If-Modify-Since 协商缓存标志 值等于上次响应的last-Modify的值
If-None-Match 协商缓存标志 值等于上次响应的ETag字符串
常见的响应头有什么?
Expires 是否强缓存 (老版本)是个将来的时间戳,有问题后来使用cache-control
Date 服务端发送资源时的服务器时间
Cache-Control 是否强缓存 他的max-age值表示在多少时间内有效
Content-Type 响应的数据类型
Content-Encoding 告诉浏览器数据压缩的格式
Content-Language 告诉浏览器使用的语言
Access-Control-Allow-Origin 指定哪些域名可以访问服务器
Access-Control-Allow-Methods 哪些方法
Access-Control-Allow-Headers 哪些请求头
Last-Modified 是否协商缓存 是个时间戳 (老版本)有问题后来使用Etag,比如编辑了文件并没有改变东西会有问题
ETag 是否使用协商缓存 由服务端为每个文件生成唯一的字符
Set-Cookie: 服务端发送的cookie
常见的通用标头有什么?
Date 表示的是格林威治标准时间,这个时间要比北京时间慢八个小时
Cache-Control 跟强缓存有关,笔者也有专门的文章介绍
Connection 连接模式,有持久连接和非持久连接 keep-alive、close
常见的实体标头有什么?
Content-Length 资源大小
Content-Language 语言
Content-Encoding 编码格式,常见的有gzip、compress、deflate、identity
对 Accept 系列字段了解多少?
对于 accept 系列字段的介绍分为四个部分: 数据格式、压缩方式、支持语言和字符集。
浏览器告知服务器自己对这四个部分想要收到特定类型的数据。
客户端接收数据想要的数据格式 accept 对于应服务端的content-type
- text: text/html, text/plain, text/css 等
- image: image/gif, image/jpeg, image/png 等
- audio/video: audio/mpeg, video/mp4 等
- application: application/json, application/javascript, application/pdf, application/octet-stream
客户端接收数据想要的数据压缩格式 accept-encoding 对应服务端的 content-encoding
- gzip: 当今最流行的压缩格式
- deflate: 另外一种著名的压缩格式
- br: 一种专门为 HTTP 发明的压缩算法
客户端接收数据想要的语言类型 accept-language 对应服务端的content-language
- accept-language: zh-CN, zh, en
客户端就收数据想要的字符集 accept-charset 服务端没有对应的content-charset, 而是直接放在了content-type中,以charset属性指定。
- Accept-Charset: charset=utf-8
- Content-Type: text/html; charset=utf-8
状态码表示什么含义?列出一些常见的状态码?
1xx 接收的请求正在处理
2xx 请求正常处理完毕
3xx 需要进行附加操作完成请求 比如重定向
4xx 服务端无法处理请求 客户端错误
5xx 服务端处理请求出错
- 101 Switching Protocols。在 HTTP 升级为 WebSocket 的时候,如果服务器同意变更,就会发送状态码 101。
- 200 成功 通常在响应体中放有数据。
- 204 No Content 含义与 200 相同,但响应头后没有 body 数据。
- 206 Partial Content 顾名思义,表示部分内容,它的使用场景为 HTTP 分块下载和断电续传,当然也会带上相应的响应头字段 Content-Range。
- 301 永久重定向 比如你的网站从 HTTP 升级到了 HTTPS 了,以前的站点再也不用了,应当返回 301,这个时候浏览器默认会做缓存优化,在第二次访问的时候自动访问重定向的那个地址。而如果只是暂时不可用,那么直接返回 302 即可,和 301 不同的是,浏览器并不会做缓存优化。
- 302 临时重定向 会改变请求方法 把 post 改为 get。
- 307 临时重定向 不会改变请求方式
- 304 Not Modified: 当协商缓存命中时会返回这个状态码。
- 400 请求错误 客户端错误
- 401 未授权
- 403 请求被拒绝
- 404 资源缺失找不到
- 405 Method Not Allowed: 请求方法不被服务器端允许。
- 408 Request Timeout: 服务器等待了太长时间。
- 409 Conflict: 多个请求发生了冲突。
- 413 Request Entity Too Large: 请求体的数据过大。
- 414 Request-URI Too Long: 请求行里的 URI 太大。
- 429 Too Many Request: 客户端发送的请求过多。
- 431 Request Header Fields Too Large 请求头的字段内容太大。
- 500 服务端错误
- 501 Not Implemented: 表示客户端请求的功能还不支持。
- 502 Bad Gateway: 服务器自身是正常的,但访问的时候出错了,啥错误咱也不知道。
- 503 Service Unavailable: 表示服务器当前很忙,暂时无法响应服务
HTTP 有哪些方法,分别有什么作用?
HTTP1.0
get 获取数据
post 新增数据
head 获取响应头,使用场景是请求可能是大文件的时候,先发送head请求判断资源大小是否能下载。
HTTP1.1
put 更新 全部更新
patch 更新,部分更新
delete 删除
options 询问,获取目的资源所支持的通信选项。非简单请求在跨域的时候会发送该请求。
trace 回显服务器收到的请求,主要用于测试或诊断
connect HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器
GET 和 POST 有什么区别?
- 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
- 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
- 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
- 从幂等性的角度,GET 是幂等的,而 POST 不是。(幂等表示执行相同的操作,结果也是相同的)
- 从 TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)
对于定长和不定长的数据,HTTP 是怎么传输的?
对于定长包体而言,发送端在传输的时候一般会带上 Content-Length, 来指明包体的长度。
对于不定长包体而言利用到另外一个头部字段 Transfer-Encoding: chunked 表示分块传输数据,设置这个字段后会自动产生两个效果:
- Content-Length 字段会被忽略
- 基于长连接持续推送动态内容
HTTP 如何处理大文件的传输?
对于几百 M 甚至上 G 的大文件来说,如果要一口气全部传输过来显然是不现实的,会有大量的等待时间,严重影响用户体验。因此,HTTP 针对这一场景,采取了范围请求的解决方案,允许客户端仅仅请求一个资源的一部分。
当然,前提是服务器要支持范围请求,要支持这个功能,就必须加上这样一个响应头: Accept-Ranges: none 用来告知客户端这边是支持范围请求的。
而对于客户端而言,它需要指定请求哪一部分,通过 Range 这个请求头字段确定,格式为 bytes=x-y。接下来就来讨论一下这个 Range 的书写格式:
- 0-499 表示从开始到第 499 个字节。
- 500- 表示从第 500 字节到文件终点。
- -100 表示文件的最后 100 个字节。
服务器收到请求之后,首先验证范围是否合法,如果越界了那么返回 416 错误码,否则读取相应片段,返回 206 状态码。同时,服务器需要添加 Content-Range 字段,这个字段的格式根据请求头中 Range 字段的不同而有所差异。具体来说,请求单段数据和请求多段数据,响应头是不一样的。
请求
// 单段数据
Range: bytes=0-9
// 多段数据
Range: bytes=0-9, 30-39
对于单段数据的请求,返回的响应如下:
HTTP/1.1 206 Partial Content
Content-Length: 10
Accept-Ranges: bytes
Content-Range: bytes 0-9/100
i am xxxxx
Content-Range 字段,0-9 表示请求的返回,100 表示资源的总大小,很好理解。
对于多段数据的请求,返回的响应如下:
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=00000010101
Content-Length: 189
Connection: keep-alive
Accept-Ranges: bytes
--00000010101
Content-Type: text/plain
Content-Range: bytes 0-9/96
i am xxxxx
--00000010101
Content-Type: text/plain
Content-Range: bytes 20-29/96
eex jspy e
--00000010101--
这个时候出现了一个非常关键的字段 Content-Type: multipart/byteranges;boundary=00000010101,它代表了信息量是这样的:
- 请求一定是多段数据请求
- 响应体中的分隔符是 00000010101
因此,在响应体中各段数据之间会由这里指定的分隔符分开,而且在最后的分隔末尾添上--表示结束。
HTTP 中如何处理表单数据的提交?
在 http 中,有两种主要的表单提交的方式,体现在两种不同的 Content-Type 取值:
- application/x-www-form-urlencoded
- multipart/form-data
对于 application/x-www-form-urlencoded 格式的表单内容,有以下特点:
- 其中的数据会被转换成以&分隔的键值对
- 非ASCII字符以 URL 编码方式编码。
// 转换过程:
{a: 1, b: 2} -> a=1&b=2
对于 multipart/form-data 而言:
- 请求头中的 Content-Type 字段会包含 boundary,且 boundary 的值由浏览器默认指定。例: Content-Type: multipart/form-data;boundary=----WebkitFormBoundaryRRJKeWfHPGrS4LKe。
- 数据会分为多个部分,每两个部分之间通过分隔符来分隔,每部分表述均有 HTTP 头部描述子包体,如 Content-Type,在最后的分隔符会加上--表示结束。
Content-Disposition: form-data;name="data1";
Content-Type: text/plain
data1
----WebkitFormBoundaryRRJKeWfHPGrS4LKe
Content-Disposition: form-data;name="data2";
Content-Type: text/plain
data2
----WebkitFormBoundaryRRJKeWfHPGrS4LKe--
HTTP/1.1 有哪些改进
1、增加持久性连接
也就是多个请求和响应可以利用同一个 TCP 连接,而不是每一次请求响应都要新建一个 TCP 连接,减少了建立和关闭连接的消耗和延迟。
2、增加管道机制
增加了管道机制,请求可以同时发出,但是响应必须按照请求发出的顺序依次返回,性能在一定程度上得到了改善。
3、分块传输
在 HTTP/1.1 版本中,可以不必等待数据完全处理完毕再返回,服务器产生部分数据,那么就发送部分数据,很明此种方式更加优秀一些,可以节省很多等待时间。
4、范围请求
HTTP/1.1 中在请求消息中引入了 range 头域,它允许只请求资源的某个部分。
5、增加 host 字段
使得一个服务器能够用来创建多个 Web 站点。
什么是 HTTP 队头阻塞?
从前面的小节可以知道,HTTP 传输是基于请求-应答的模式进行的,报文必须是一发一收,但值得注意的是,里面的任务被放在一个任务队列中串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理。这就是著名的 HTTP 队头阻塞问题。
HTTP1.1 如何解决 HTTP 的队头阻塞问题?
使用并发连接和域名分片。
并发连接
对于一个域名允许分配多个长连接,那么相当于增加了任务队列,不至于一个队伍的任务阻塞其它所有任务。在 RFC2616 规定过客户端最多并发 2 个连接,不过事实上在现在的浏览器标准中,这个上限要多很多,Chrome 中是 6 个。 但其实,即使是提高了并发连接,还是不能满足人们对性能的需求。
域名分片
一个域名不是可以并发 6 个长连接吗?那我就多分几个域名。 比如 content1.randy.com 、content2.randy.com。 这样一个 randy.com 域名下可以分出非常多的二级域名,而它们都指向同样的一台服务器,能够并发的长连接数更多了,事实上也更好地解决了队头阻塞的问题。
HTTP/2 有哪些改进?
1、头部压缩
客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
2、二进制传输
首先,HTTP/2 认为明文传输对机器而言太麻烦了,不方便计算机的解析,因为对于文本而言会有多义性的字符,比如回车换行到底是内容还是分隔符,在内部需要用到状态机去识别,效率比较低。于是 HTTP/2 干脆把报文全部换成二进制格式,全部传输 01 串,方便了机器的解析。
原来 Headers + Body 的报文格式如今被拆分成了一个个二进制的帧,用 Headers 帧存放头部字段,Data 帧存放请求体数据。分帧之后,服务器看到的不再是一个个完整的 HTTP 请求报文,而是一堆乱序的二进制帧。这些二进制帧不存在先后关系,因此也就不会排队等待,也就没有了 HTTP 的队头阻塞问题。
3、多路复用
通信双方都可以给对方发送二进制帧,这种二进制帧的双向传输的序列,也叫做流(Stream)。HTTP/2 用流来在一个 TCP 连接上来进行多个数据帧的通信,这就是多路复用的概念。
首先要声明的是,所谓的乱序,指的是不同 ID 的 Stream 是乱序的,但同一个 Stream ID 的帧一定是按顺序传输的。二进制帧到达后对方会将 Stream ID 相同的二进制帧组装成完整的请求报文和响应报文。当然,在二进制帧当中还有其他的一些字段,实现了优先级和流量控制等功能。
4、服务器推送
外值得一说的是 HTTP/2 的服务器推送(Server Push)。在 HTTP/2 当中,服务器已经不再是完全被动地接收请求,响应请求,它也能新建 stream 来给客户端发送消息,当 TCP 连接建立之后,比如浏览器请求一个 HTML 文件,服务器就可以在返回 HTML 的基础上,将 HTML 中引用到的其他资源文件一起返回给客户端,减少客户端的等待。
HTTPS
https 是安全的 http 协议。端口号是443。
HTTPS 为什么让数据传输更安全?
谈到 HTTPS, 就不得不谈到与之相对的 HTTP。HTTP 的特性是明文传输,因此在传输的每一个环节,数据都有可能被第三方窃取或者篡改,具体来说,HTTP 数据经过 TCP 层,然后经过 WIFI 路由器、运营商和目标服务器,这些环节中都可能被中间人拿到数据并进行篡改,也就是我们常说的中间人攻击。 为了防范这样一类攻击,我们不得已要引入新的加密方案,即 HTTPS。 HTTPS 并不是一个新的协议, 而是一个加强版的 HTTP。其原理是在 HTTP 和 TCP 之间建立了一个中间层,当 HTTP 和 TCP 通信时并不是像以前那样直接通信,直接经过了一个中间层(TLS、SSL)进行加密,将加密后的数据包传给 TCP, 响应的,TCP 必须将数据包解密,才能传给上面的 HTTP。这个中间层也叫安全层。安全层的核心就是对数据加解密。
HTTPS加密方式有哪些?
- 对称加密 加密解密使用同一把密钥 传输密钥不太安全
- 非对称加密 公钥是公开的使用公钥加密 私钥只有自己知道使用私钥解密
什么是 TLS、SSL
通俗的讲,TLS、SSL 其实是类似的东西,SSL 是个加密套件,负责对 HTTP 的数据进行加密。TLS 是 SSL 的升级版。现在提到 HTTPS,加密套件基本指的是 TLS。
TLS、SSL 握手
- 浏览器向服务器发送 client_random 和加密方法列表。
- 服务器接收到,返回 server_random、加密方法以及公钥。
- 浏览器接收,接着生成另一个随机数 pre_random, 并且用公钥加密,传给服务器。
- 服务器用私钥解密这个被加密后的 pre_random。
- 现在浏览器和服务器有三样相同的凭证:client_random、server_random 和 pre_random。然后两者用相同的加密方法混合这三个随机数,生成最终的密钥。然后浏览器服务器使用该秘钥进行对称加密传输。所以HTTPS的加密传输是对称和非对称结合的方式。
有了对称非对称加密传输就一定安全吗?
尽管通过两者加密方式的结合,能够很好地实现加密传输,但实际上还是存在一些问题。黑客如果采用 DNS 劫持,将目标地址替换成黑客服务器的地址,然后黑客自己造一份公钥和私钥,照样能进行数据传输。而对于浏览器用户而言,他是不知道自己正在访问一个危险的服务器的。 事实上 HTTPS 在上述结合对称和非对称加密的基础上,又添加了数字证书认证的步骤。其目的就是让服务器证明自己的身份。
数字证书
数字证书是可信任组织颁发给特定对象的认证。
为了获取这个证书,服务器运营者需要向第三方认证机构获取授权,这个第三方机构也叫 CA(Certificate Authority), 认证通过后 CA 会给服务器颁发数字证书。
这个数字证书有两个作用:
- 服务器向浏览器证明自己的身份。
- 把公钥传给浏览器。
怎么验证证书的有效性?
- 服务器把证书发送过来,证书上有一些基本信息和一个签名,签名的内容是摘要算法和摘要密文,摘要密文(指纹)是基本信息通过摘要算法计算出来的 hash 值。签名是证书机构通过私钥加密的。
- 客户端寻找内置证书,判断服务器发来的证书是否在自己内置的证书列表,找到了就使用内置证书的公钥解密签名得到指纹内容和指纹算法,然后使用指纹算法加密基本信息得到 hash(指纹内容),拿这两个 hash 对比判断是否一致,一致就通过。
摘要算法
数字摘要是采用 Hash 函数将需要加密的明文 “摘要” 成一串固定长度(128位)的密文,这串密文又称为数字指纹,它有固定长度,而且不同的明文摘要成密文,其结果总是不同,而同样的明文摘要肯定是相同得。数字摘要是 HTTPS 能确保数据完整性和防篡改的根本原因。
数字签名
数字签名是非对称加密和数字摘要两项技术的应用,它将摘要算法和摘要密文用发送者的私钥加密,和原文一起发给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用解密出来的摘要算法函数对收到的原文生成一个摘要密文,与解密的摘要密文对比。如果一样,那就说明收到的信息是完整的。否则说明信息被修改过,因此数字签名能够验证信息的完整性。
HTTPS 保证安全传输的原因
- https 是使用了非对称加密和对称加密相结合的方式。
- https 并不是直接通过非对称加密传输过程,而是有握手过程,握手过程主要是和服务器做通讯,通过非对称加密的方式生成对称的私有秘钥,最后通过该秘钥对称加密传输数据。
- 使用了证书,证书验证过程保证了对方是合法的,并且中间人无法通过伪造证书方式进行攻击。
HTTP 和 HTTPS 异同?
- HTTP
- HTTP 端口是 80。
- HTTP 使用明文 内容可能会被窃听。
- HTTP 不验证通信方的身份 可能会被伪装。
- HTTP 无法证明报文的完整性 可能会被篡改。
- HTTP 与 TCP 进行通信,而 https 与 SSL 或者 TLS 层通信。
- HTTPS
- HTTPS 端口是 443。
- HTTPS 多了证书这一概念。
- HTTPS 不是新的协议 是身披 SSL/TLS 协议外壳的 HTTP。
- HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,HTTPS 运行在 SSL/TLS 之上,SSL/TLS 运行在 TCP 之上,所有传输的内容都经过加密的。
- HTTPS 采用对称加密和非对称加密两者并用的加密方式。
后记
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!