Para 0 概述
第一部分主要包含了一个网址的解析过程,OSI模型,TCP模型的讲解,还有TCP/UDP协议的分析,以及常见状态码。
Para1 从输入一个网址开始
不知道各位是否有个好奇?浏览器是如何根据网站找到对应的服务器并返回内容给我们的。如果你是一个普通人,你可以把这篇文章当作科普来看,如果你是一个软件从业者,你需要对网络应用如何工作有一个完整的层次化的认知,同样这里也包括这些应用所用到的技术:像浏览器,HTTP,HTML,网络服务器,需求处理等等。
Para 1.1 输入网址
这里以百度为例子。
Para 1.2 查找对应的ip地址
这里就涉及到我们需要了解的第一个知识点:DNS。
DNS中文名为域名解析系统,是互联网的一项服务。它作为将域名和IP地址互相映射的一个分布式数据库,能够使人更方便地访问互联网。DNS使用UDP的端口53。
在浏览器中DNS的查找过程如下:
- 浏览器缓存 – 浏览器会缓存DNS记录一段时间。 有趣的是,操作系统没有告诉浏览器储存DNS记录的时间,这样不同浏览器会储存个自固定的一个时间(2分钟到30分钟不等)。
- 系统缓存 – 如果在浏览器缓存里没有找到需要的记录,浏览器会做一个系统调用(windows里是gethostbyname)。这样便可获得系统缓存中的记录。
- 路由器缓存 – 接着,前面的查询请求发向路由器,它一般会有自己的DNS缓存。
- ISP DNS 缓存 – 接下来要check的就是ISP缓存DNS的服务器。在这一般都能找到相应的缓存记录。
- 递归搜索 – 你的ISP的DNS服务器从跟域名服务器开始进行递归搜索,从.com顶级域名服务器到Facebook的域名服务器。一般DNS服务器的缓存中会有.com域名服务器中的域名,所以到顶级服务器的匹配过程不是那么必要了。
Para 1.3 浏览器向web服务器发送一个HTTP请求
在通过DNS服务器找到对应的ip地址之后,浏览器会向web服务器发送一个HTTP请求到百度所在的服务器。
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
GET 这个请求定义了要读取的URL: “www.baidu.com”。 浏览器自身定义 (User-Agent 头), 和它希望接受什么类型的相应 (Accept and Accept-Encoding 头). Connection头要求服务器为了后边的请求不要关闭TCP连接。
当然如果涉及到鉴权的请求,该request请求中还会包含对应的Session或Cookie。Cookies会以文本文档形式存储在客户机里,每次请求时发送给服务器。
这里又涉及到一块知识点:Cookie和Session。
==============================================================
Cookie基本原理
Cookie是一段不超过4KB的小型文本数据,由一个名称(Name)、一个值(Value)和其它几个用于控制Cookie有效期、安全性、使用范围的可选属性组成。
(1)Name/Value:设置Cookie的名称及相对应的值,对于认证Cookie,Value值包括Web服务器所提供的访问令牌。
(2)Expires属性:设置Cookie的生存期。有两种存储类型的Cookie:会话性与持久性。Expires属性缺省时,为会话性Cookie。
==============================================================
Session基本原理
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中,安全性优于Cookie,同时当用户浏览器推出的时候Session就会失效。
==============================================================
安全威胁
Cookie捕获和重放:用户可以通过非法手段监听用户网络拦截用户请求包,或读取硬盘中存储的Cookie信息实现获取到用户的Cookie信息,通过再通过mock的方式重放给后台,此时后台就会认为是合法请求从而达到了入侵。
CSRF攻击:跨站请求伪造(Cross-Site Request Forgery,简称CSRF)是指,攻击者可能利用网页中的恶意代码强迫受害者浏览器向被攻击的Web站点发送伪造的请求,篡夺受害者的认证Cookie等身份信息,从而假冒受害者对目标站点执行指定的操作。
Para 1.4 服务器返回给客户端相应
在服务器收到请求之后,会返回给客户端相应结果,下面就是访问百度的返回结果。
HTTP/1.1 200 OK
Bdpagetype: 2
Bdqid: 0x9989168a00155fc1
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Sat, 20 Mar 2021 16:18:56 GMT
Expires: Sat, 20 Mar 2021 16:18:56 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=88; path=/
Set-Cookie: BD_HOME=1; path=/
此时服务器返回了200 OK代表资源已经请求成功了,同时Connection表示了此时和服务器保持了连接,Content-Type定义了响应结果的数据格式。
Para 1.5 浏览器发起正式请求
这就和刚开始的发送第一个请求类似了,不多做分析。
Para 1.6 服务器解析请求
服务器接收到获取请求,然后处理并返回一个响应。
这表面上看起来是一个顺向的任务,但其实这中间发生了很多有意思的东西- 就像作者博客这样简单的网站,何况像baidu那样访问量大的网站呢!
- Web 服务器软件
web服务器软件(像IIS和阿帕奇)接收到HTTP请求,然后确定执行什么请求处理来处理它。请求处理就是一个能够读懂请求并且能生成HTML来进行响应的程序(像ASP.NET,PHP,RUBY…)。
这里看到百度的Server类型为BWS,猜测为Baidu Web Server估计是自研或基于开源改造的服务器。
- 请求处理
请求处理阅读请求及它的参数和cookies。它会读取也可能更新一些数据,并讲数据存储在服务器上。然后,需求处理会生成一个HTML响应。
Para 1.7 服务器响应结果
Para 1.8 浏览器解析页面
浏览器收到服务器响应的结果之后便开始解析资源,首先渲染HTML,然后根据对应的css和js拉取对应的资源,从而完成渲染。
Para 1.9 断开TCP链接
当数据完成请求到返回的过程之后,根据Connection的Keep-Alive属性可以选择是否断开TCP连接,HTTP/1.1一般支持同一个TCP多个请求,而不是1.0版本下的完成一次请求就发生断开。TCP的断开与连接不一样,断开可以分为主动关闭和被动关闭,需要经过4次握手。当浏览器需要的全部数据都已经加载完毕,一个页面就显示完了。
Para 2 网络世界的模型
在网络世界,互联网通过模型来实现网络数据的解析,渲染,传输等操作。其中最经典的模型有OSI七层模型和TCP/IP的四层模型。
下面是二者模型的基本对比。
Para 2.1 OSI七层模型
- OSI: open system interconnection 开放式系统互联参考模型
- OSI 和TCP/IP 的对应关系和协议
OSI模型各层的基本作用:
重点层:
Para 3 常见协议
Para 3.1 TCP协议
TCP将用户数据打包构成报文段,它发送数据时启动一个定时器,另一端收到数据进行确认,对失序的数据重新排序,丢弃重复的数据。TCP提供一种面向连接的可靠的字节流服务,面向连接意味着两个使用TCP的应用(B/S)在彼此交换数据之前,必须先建立一个TCP连接,类似于打电话过程,先拨号振铃,等待对方说喂,然后应答。在一个TCP连接中,只有两方彼此通信。
TCP可靠性来自于:
(1)应用数据被分成TCP最合适的发送数据块
(2)当TCP发送一个段之后,启动一个定时器,等待目的点确认收到报文,如果不能及时收到一个确认,将重发这个报文。
(3)当TCP收到连接端发来的数据,就会推迟几分之一秒发送一个确认。
(4)TCP将保持它首部和数据的检验和,这是一个端对端的检验和,目的在于检测数据在传输过程中是否发生变化。(有错误,就不确认,发送端就会重发)
(5)TCP是以IP报文来传送,IP数据是无序的,TCP收到所有数据后进行排序,再交给应用层
(6)IP数据报会重复,所以TCP会去重
(7)TCP能提供流量控制,TCP连接的每一个地方都有固定的缓冲空间。TCP的接收端只允许另一端发送缓存区能接纳的数据。
(8)TCP对字节流不做任何解释,对字节流的解释由TCP连接的双方应用层解释。
Para 3.2 UDP协议
UDP是传输层的协议,功能即为在IP的数据报服务之上增加了最基本的服务:复用和分用以及差错检测。
UDP提供不可靠服务,具有TCP所没有的优势:
- UDP无连接,时间上不存在建立连接需要的时延。空间上,TCP需要在端系统中维护连接状态,需要一定的开销。
- 分组首部开销小**,TCP首部20字节,UDP首部8字节。
- UDP没有拥塞控制,应用层能够更好的控制要发送的数据和发送时间,网络中的拥塞控制也不会影响主机的发送速率。某些实时应用要求以稳定的速度发送,能容 忍一些数据的丢失,但是不能允许有较大的时延(比如实时视频,直播等)
- UDP提供尽最大努力的交付,不保证可靠交付。所有维护传输可靠性的工作需要用户在应用层来完成。没有TCP的确认机制、重传机制。如果因为网络原因没有传送到对端,UDP也不会给应用层返回错误信息
- UDP是面向报文的,对应用层交下来的报文,添加首部后直接乡下交付为IP层,既不合并,也不拆分,保留这些报文的边界。对IP层交上来UDP用户数据报,在去除首部后就原封不动地交付给上层应用进程,报文不可分割,是UDP数据报处理的最小单位。
正是因为这样,UDP显得不够灵活,不能控制读写数据的次数和数量。比如我们要发送100个字节的报文,我们调用一次sendto函数就会发送100字节,对端也需要用recvfrom函数一次性接收100字节,不能使用循环每次获取10个字节,获取十次这样的做法。 - UDP常用一次性传输比较少量数据的网络应用,如DNS,SNMP等,因为对于这些应用,若是采用TCP,为连接的创建,维护和拆除带来不小的开销。UDP也常用于多媒体应用(如IP电话,实时视频会议,流媒体等)数据的可靠传输对他们而言并不重要,TCP的拥塞控制会使他们有较大的延迟,也是不可容忍的。
Para 3.3 HTTP协议
Para 3.3.1 HTTP 0.9
0.9和1.0这两个版本,就是最传统的 request – response的模式了,HTTP 0.9版本的协议简单到极点,请求时,不支持请求头,只支持 GET
方法,没了。HTTP 1.0 扩展了0.9版,其中主要增加了几个变化:
- 在请求中加入了HTTP版本号,如:
GET /coolshell/index.html HTTP/1.0
- HTTP 开始有 header了,不管是request还是response 都有header了。
- 增加了HTTP Status Code 标识相关的状态码。
- 还有
Content-Type
可以传输其它的文件了。
Para 3.3.2 HTTP 1.0
HTTP 1.0 开始让这个协议变得很文明了,一种工程文明。因为:
- 一个协议有没有版本管理,是一个工程化的象征。
- header是协议可以说是把元数据和业务数据解耦,也可以说是控制逻辑和业务逻辑的分离。
- Status Code 的出现可以让请求双方以及第三方的监控或管理程序有了统一的认识。最关键是还是控制错误和业务错误的分离。
Para 3.3.3 HTTP 1.1
HTTP/1.1 主要解决了HTTP 1.0的网络性能的问题,以及增加了一些新的东西:
- 可以设置
keepalive
来让HTTP重用TCP链接,重用TCP链接可以省了每次请求都要在广域网上进行的TCP的三次握手的巨大开销。这是所谓的“HTTP 长链接” 或是 “请求响应式的HTTP 持久链接”。英文叫 HTTP Persistent connection. - 然后支持pipeline网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。(注:非幂等的POST 方法或是有依赖的请求是不能被pipeline化的)
- 支持 Chunked Responses ,也就是说,在Response的时候,不必说明
Content-Length
这样,客户端就不能断连接,直到收到服务端的EOF标识。这种技术又叫 “服务端Push模型”,或是 “服务端Push式的HTTP 持久链接” - 还增加了 cache control 机制。
- 协议头注增加了 Language, Encoding, Type 等等头,让客户端可以跟服务器端进行更多的协商。
- 还正式加入了一个很重要的头——
HOST
这样的话,服务器就知道你要请求哪个网站了。因为可以有多个域名解析到同一个IP上,要区分用户是请求的哪个域名,就需要在HTTP的协议中加入域名的信息,而不是被DNS转换过的IP信息。 - 正式加入了
OPTIONS
方法,其主要用于CORS – Cross Origin Resource Sharing 应用。
Para 3.3.4 HTTP 2.0
HTTP/2.0和HTTP/1.1最主要的不同是:
- HTTP/2是一个二进制协议,增加了数据传输的效率。
- HTTP/2是可以在一个TCP链接中并发请求多个HTTP请求,移除了HTTP/1.1中的串行请求。
- HTTP/2会压缩头,如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。这就是所谓的HPACK算法。
- HTTP/2允许服务端在客户端放cache,又叫服务端push,也就是说,你没有请求的东西,我服务端可以先送给你放在你的本地缓存中。比如,你请求X,我服务端知道X依赖于Y,虽然你没有的请求Y,但我把把Y跟着X的请求一起返回客户端。
Para 4 常见状态码
Para 4.1 2xx
200 OK:表示从客户端发送给服务器的请求被正常处理并返回;
204 No Content:表示客户端发送给客户端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分(没有资源可以返回);
206 Patial Content:表示客户端进行了范围请求,并且服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。
Para 4.2 3XX
301 Moved Permanently:永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;
302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;
301与302的区别:前者是永久移动,后者是临时移动(之后可能还会更改URL)
303 See Other:表示请求的资源被分配了新的URL,应使用GET方法定向获取请求的资源;
302与303的区别:后者明确表示客户端应当采用GET方式获取资源
304 Not Modified:表示客户端发送附带条件(是指采用GET方法的请求报文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的请求时,服务器端允许访问资源,但是请求为满足条件的情况下返回改状态码;
307 Temporary Redirect:临时重定向,与303有着相同的含义,307会遵照浏览器标准不会从POST变成GET;(不同浏览器可能会出现不同的情况);
Para 4.3 4xx
400 Bad Request:表示请求报文中存在语法错误;
401 Unauthorized:未经许可,需要通过HTTP认证;
403 Forbidden:服务器拒绝该次访问(访问权限出现问题)
404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;
Para 4.4 5xx
500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;
503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;