http 二进制_计算机网络-HTTP

  • Post author:
  • Post category:其他


HTTP请求

当我们通过DNS解析获取到对应的服务IP地址,接下来就可以进行HTTP请求了。

那么什么是HTTP请求呢?HTTP请求本质上

是把HTTP报文通过被包裹在TCP报文内的方式,发送到服务端指定端口的过程。

TCP概念我们之后会说,这里首先简单的介绍一下HTTP请求的基础概念:

请求报文



响应报文

请求报文

当我们发出一个HTTP请求时,我们的HTTP请求可以用下图来概括

89ee7e8538bcc8cec6300d90569a2006.png

其中1,2,3为请求行,4为请求头,5为请求体。所以我们把HTTP请求组成是这样的

871a3c27ab463cf04d1e333b9ecdd439.png

值得我们注意的是:1.

请求行中的请求协议版本

。(不同的http版本会有不同的特性,我们做优化时需要考虑到http协议的特性去做)2.

请求头中的客户端信息

。(我们之后做HTTP缓存的优化时就要应用到这里的相关属性),这里我们只需要对应请求报文有个大概的了解即可。

响应报文

当我们的服务器收到请求时,会给我们返回一些信息,这就是HTTP的响应报文。响应报文和我们的请求报文类似,它大概长这个样子

4857c6113925797fff4072b5d14eb4c8.png

其中1、2为响应行,3为响应头,4为响应体,看起来和HTTP请求报文的结构类似,HTTP响应组成是这样的

7777af3b3f373fd796128fe5cb119e02.png

这里我们需要注意的:1.

状态码&状态描述

。(这里可以快速定位分析多种响应状态)2.

响应头中的服务端信息

。(我们之后做HTTP缓存的优化时也要应用到这里的相关属性)

其实我们HTTP基本上就由

HTTP请求



HTTP响应

两部分组成。目前我们对于HTTP请求报文和响应报文已经有一个比较简单的大体认知,之后我们讲把之前提到的几个关键点逐步展开进行分析。另外HTTP还有一个兄弟叫HTTPS,我们也会介绍一下HTTPS的实现原理。所以基本上HTTP这里的知识点有以下几部分:

  • HTTP协议版本特征,以及HTTP不同版本协议的区别
  • 结合HTTP请求头与响应头进行HTTP缓存策略
  • HTTP状态码与状态描述
  • HTTPS

HTTP版本区别

HTTP 0.9

只支持GET请求、只响应HTML文件,无状态码和错误代码


HTTP 0.9

HTML文档传输

<!-- HTTP Request -->
GET /mypage.html
<!-- HTTP Response -->
<HTML>
这是一个非常简单的HTML页面
</HTML>

HTTP 1.0

相比于0.9,1.0版本在可用性上做了极大的拓展,新增特性如下:

  1. 在请求头中增加版本协议信息用来区别HTTP版本
  2. 新增状态码
  3. 新增HTTP头
  4. 由于新增的HTTP头中的Content-Type可以指定其他的文本解析方式,所以可以传输HTML类型之外的文件


HTTP 1.0

HTML文档传输

<!-- HTTP Request -->
GET /mypage.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
<!-- HTTP Response -->
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html
<HTML> 
一个包含图片的页面
  <IMG SRC="/myimage.gif">
</HTML>


HTML 1.0

其他文件传输(此处以图片为例)

<!-- HTTP Request -->
GET /myimage.gif HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
<!-- HTTP Response -->
200 OK
Date: Tue, 15 Nov 1994 08:12:32 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/gif
(这里是图片内容)

HTTP 1.1


HTTP 1.0

由于实现方式不一致导致在各个地方使用混乱,为了解决一致性问题,

HTTP 1.1

版本发布,这也是我们目前最常见的HTTP版本。


HTTP 1.1

版本相比于1.0版本,不仅消除了大量歧义内容,同时也引进了如下的功能改进。

  1. 持久化链接(支持TCP链接复用)
  2. 支持管线化技术(pipelining:在上一个请求响应之前可以发送第二个请求)但可惜的是只存在理论阶段,并没有被实现支持
8bf28bea879dfb19bb14c906b609ed51.png
  1. 支持响应分块:chunked
  2. 支持额外的缓存控制特性
  3. If-Modefied-Since
  4. If-Unmodified-Since
  5. If-Match
  6. If-None-Match
  7. ET-tag
  8. 支持内容协商机制(客户端和服务端之间按照最合适的

    语言



    编码



    类型

    进行传输):Accept-XXX
  9. 支持Host头(这个功能使不同的域名可以配置在同一个IP服务器下面):Host


HTTP 1.1

传输

<!-- HTTP Request -->
GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
<!-- HTTP Response -->
200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a"
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding

REST:也是因为HTTP拓展到Web应用,原来HTTP只读(其他逻辑都在服务器)的方式已经不能被满足了。所以新的HTTP使用模式(representational state transfer)被设计出来,它让我们可以通过不同的请求方式(API)来查看/操作数据,而不是服务器进行修改,这就是我们的REST模式

HTTP 2.0

由于网页应用的复杂度越来越高,更多的请求被使用HTTP协议进行传输。而使用

HTTP 1.1

面对一些场景会有着性能问题,比如说:


  1. 队头阻塞

    :HTTP 1.1无法通过单个链接进行并发请求,所以浏览器需要开启多个链接加快进程。

  2. 昂贵的链接

    :由于1和浏览器的域名链接限制,导致网站请求资源的性能瓶颈。

  3. HTTP管线化

    :当有一个大/慢的请求,使用管线化技术会导致后续请求都受影响。

HTTP管线化瓶颈:就像在超市收银台或者银行柜台排队时一样,你并不知道前面的

顾客

是干脆利索的还是会跟收银员/柜员磨蹭到世界末日(不管怎么说,服务器(即收银员/柜员)是要按照顺序处理请求的,如果

前一个请求非常耗时(顾客磨蹭)

,那么后续请求都会受到影响。

为了解决这些问题,

HTTP 2.0

应运而生,

HTTP 2.0

拥有以下特性:

  1. 二进制分帧(由文本协议转化为二进制协议)
  2. 多路复用(并行的请求可以在同一链接中进行,解除了

    HTTP 1.x

    的顺序和阻塞约束)
  3. 压缩headers(去除了传输重复数据,比如协议之类的只会传输一次)
  4. 支持服务器推送缓存
  5. 支持Alt-Svc(允许给定资源的位置和资源鉴定),允许更智能的CDN缓冲机制
  6. 支持Client-Hints(通过传输屏幕分辨率、设备尺寸… 传输合适的响应式资源,如:对应图片资源)
  7. cookie引入安全前缀以保证cookie没有被修改过

其中最重要的特性就是

多路复用

,它解决了

HTTP 1.1

中的队头阻塞问题。那么

HTTP 2.0

的多路复用是如何实现的呢?

首先明确一个概念:HTTP 2.0的

多路复用

和HTTP 1.1开启

keep-alive

是不一样的,keep-alive虽然开启之后也可以使用一条TCP链接,但是本质上还是属于一问一答的形式,也就是一条传输完才可以传输下一条。而HTTP 2.0中的

多路复用

就不一样了,多路复用可以并发好几个请求在一条TCP链接中进行传输,也就是一个域名下面的多个资源一起请求和传输。

那么聪明的小伙伴一定有问题了:那么多条请求传输,

HTTP 2.0

是如何做到数据不会相互污染呢?这就要得益于HTTP 2.0的两个重要概念:帧(frame)和流(steam)。

这是HTTP帧:

d0f540609962f6056d276f51389285d4.png

这是HTTP流:

59332ea5fb665cd7c9462532456749fb.png

我们之前有说过

HTTP 2.0讲文本协议转化为二进制协议

,我们的

HTTP 2.0

传输就是基于二进制帧的。在

HTTP 2.0

中每条TCP链接里面会存在多条双向数据流,里面的每个数据流都会有一个唯一标识和优先级。而流里面就是由我们的二进制帧组成,二进制帧里面会有头部信息标识来标明自己属于哪一条数据流。

通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。


那为什么HTTP1.1版本不可以呢?

原因是:HTTP/1.1 不是二进制传输,而是通过文本进行传输。由于没有流的概念,在使用并行传输(多路复用)传递数据时,接收端在接收到响应后,并不能区分多个响应分别对应的请求,所以无法将多个响应的结果重新进行组装,也就实现不了多路复用。

HTTPS

从上面我们可以看到HTTP协议随着不断的演进,传输的效率变得越来越高。但是除了提高传输效率,我们的传输安全性也是一个不可忽略的大问题,我们之前在介绍HTTP请求时曾说过:

HTTP请求本质上

是把HTTP报文通过被包裹在TCP报文内的方式,发送到服务端指定端口的过程。


那么如果我们的请求被拦截,HTTP报文就会被读取/修改,就会导致我们的信息泄露。

为了避免这种情况的发生,我们想到了一个方法:

把HTTP报文先进行一次加密(SSL/TSL),然后再把加密后的HTTP报文放进TCP报文中,这样就算是请求被拦截,但是由于HTTP报文已经被加密,别人也就获取不到我们的真实信息了

,这就是HTTPS。

SSL和TSL的加密方式分为:对称加密和非对称加密,其中原理会涉及到私钥、公钥的概念。想要更详细的了解可以参考这里

HTTP状态码与状态描述

HTTP状态码是HTTP中很重要的概念知识,通过HTTP状态码的返回我们可以快速的定位响应状态,接下来我们大体的对于状态码进行一个大体介绍:

  • 1XX:消息,代表进行中状态
  • 100:表明部分请求服务器已接收,需继续发送剩余响应
  • 2XX:已完成状态
  • 200:成功
  • 202:成功但未处理
  • 204:成功但无返回
  • 3XX:转发/重定向
  • 301:永久移动的转发/重定向
  • 302:临时移动的转发/重定向
  • 304:not Modified未修改,缓存
  • 4XX:请求/客户端错误
  • 400:服务器不理解请求语法
  • 403:服务器拒绝访问
  • 404:资源找不到
  • 412:未满足前提条件
  • 5XX:服务端错误
  • 500:未知错误
  • 503:服务器过载/维护中

HTTP缓存

试想一下,如果客户端发起的每个请求都需要服务器进行计算响应,那并发数将会收到极大的限制。此时缓存可以说是一个十分重要的优化手段,合理的缓存策略可以极大的减少请求的开销。接下来我们就来介绍一下HTTP缓存。

宏观上HTTP缓存可以分为两大类:

私有缓存(强缓存)



共享缓存(协商缓存)

私有缓存可以大致理解为是我们本地浏览器所做的缓存,当这个窗口被关闭后里面的缓存就失效了,由于这个缓存是存在于我们本地的浏览器中,并不一定与别人的客户端进行共享,所以叫做私有缓存。

而共享缓存可以理解为是服务器的缓存,无论是哪个用户请求回来都会读取这部分缓存内容,所以叫做共享缓存。

私有缓存

  • Pragma:HTTP 1.0中的缓存兼容字段
  • Expires:缓存有效时间,会与本机时间进行对比,超出则请求资源(但是由于对比的是本机时间,所以不一定准确)


Expires: Wed ,21 Oct 2015 07:28:00 GMT



  • Expires

    为0,则表示资源已过期
  • 若存在

    Cache-Control

    头且值为

    max-age



    s-max-age

    ,则Expires字段失效
  • Cache-Control:缓存策略
  • no-store:无缓存
  • no-cache:缓存,但是需要服务器验证(验证Last-Modified、ETag等字段)
  • max-age:相对过期时间,单位为s

共享缓存

  • (响应)Last-Modified:文件的最后修改时间
  • (请求)If-Modified-Since:比较资源最后的更新时间是否一致,一致304,不一致200
  • (请求)If-Unmodified-Since:日期之后,且未更新才接受,否则412(断点续传)
  • (响应)Etag:资源特定标识
  • (请求)If-Match:比较Etag是否一致,一致200,不一致412
  • (请求)If-None-Match:比较Etag是否不一致,不一致200,一致304

缓存优先级

私有缓存 > 共享缓存

Cache-Control > Expires > Pragma > Tag > Last-Modified

引用

https://www.zhihu.com/question/306768582/answer/595200654

https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/14

https://segmentfault.com/a/1190000020801458?utm_source=tag-newest