计算机网络1

一、HTTP协议

1、理解HTTP协议

HTTP协议:超文本 传输 协议

协议:

a、协议必须要有两个或多个参与者,也就是“协”

b、协议是对参与者的一种行为约定和规范,也就是“议”

HHTP第一层含义:HTTP是一个用在计算机世界里的协议。使用计算机能够理解的语言确立了一种计算机之间交流通信的规范以及相关的各种控制和错误处理方法

传输:传输就是把一堆东西从a点搬到b点

a、HTTP是一个“双向协议”。发起传输动作的是请求方;接到传输的叫做应答方或响应方。

b、数据虽然是在a和b之间传输,但是并没有限制只有a和b这两个角色,允许中间有“中转”或者“接力”。

HTTP的第二层含义:HTTP是一个在计算机世界里专门用来在两点之间传输数据的约定和规范。

文本:表示HTTP传输的不是TCP/UDP这些底层协议里被切分的杂乱无章的二进制包,而是完整的、有意义的数据,可以被浏览器、服务器这些上层应用程序处理。(图片、音频、视频甚至是压缩包)

超文本:“超文本就是超越了普通文本的文本”,是文字、图片、音频和视频等的混合体,最关键的是含有“超链接”,可以从一个“超文本”跳跃到另一个“超文本”。最熟悉的超文本是HTML

HTTP是什么?:HTTP是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。

HTTP不是什么?:HTTP是构建互联网的重要基础技术,它没有实体,依赖许多其他技术来实现,但同时许多技术也都依赖于它。HTTP不是服务器、应用程序、操作系统、互联网、编程语言、HTML以及不是一个孤立的协议。

二、与HTTP相关的各种概念

1、与HTTP有关系的各种应用技术

a、网络世界

互联网是由许多个规模略小的网络(局域网、广域网、固定网络、移动网络)连接而成的。

b、浏览器

浏览器:Web Browser,检索、查看互联网上网页资源的应用程序。HTTP协议中的请求方

c、Web服务器

Web服务器:Web Server,HTTP协议的响应方

硬件层面:物理形式或“云”形式的服务器,大多数情况下它可能不是一台服务器,而是利用反向代理、负载均衡等技术组成的庞大集群。是“虚拟”的

软件层面:提供Web服务的应用程序,运行在硬件含义的服务器上。利用强大的硬件能力响应海量的客户端HTTP请求处理磁盘上的网页、图片等静态文件,或者把请求转发给后面的Tomcat、Node.js等业务应用,返回动态信息。

d、CDN

浏览器和服务器是HTTP协议的两个端点。浏览器不会直接连接服务器,中间就有一个重要角色CDN。

CDN:是内容分发网络,应用了HTTP协议里的缓存和代理技术,代替源端响应客户端的请求

e、爬虫

浏览器是一种用户代理,代替我们访问互联网。

爬虫:一种可以自动访问Web资源的应用程序。用到的基本技术是HTTP和HTML

f、HTML/WebService/WAF

HTML:HTTP协议传输的主要内容之一,描述超文本页面。

WebService:有W3C定义的应用服务开发规范,一个基于Web(HTTP)的服务架构技术

WAF:网络应用防火墙,与硬件防火墙类似。是应用层面的防火墙,位于Web服务器之前。

小结:

1、互联网绝大部分资源都是用HTTP协议传输。

2、浏览器是HTTP协议里的请求方,服务器是HTTP协议里的应答方,常用的有Apache和Nginx。

3、CDN位于浏览器和服务器之间,主要起到缓存加速的作用。

4、爬虫是另一类请求方,是自动访问网络资源的程序。

2、各种HTTP相关协议

a、TCP/IP

TCP/IP协议:实际上是一系列网络通信协议的统称,其中两个最核心的协议是TCP和IP,其他的还有UDP、ICMP、ARP等,共同构成了一个复杂但有层次的协议栈。

协议栈有四层,最上层:“应用层”,最下层:“链接层”,TCP属于传输层,IP属于网际层。

IP协议:Internet Protocol的缩写。主要目的是解决寻址好路由问题,以及如何在两点之间传送数据包。IP协议使用IP地址的概念来定位互联网上每一台计算机

TCP协议:Transmission Control Protocol的缩写,传输控制协议位于IP协议之上,基于IP协议提供可靠的(保证数据不丢失)字节流(保证数据完整)形式的通信,是HTTP协议实现的基础

b、DNS

DNS:域名系统,用有意义的名字来作为IP地址的等价替代

DNS中域名用“.”分隔成多个单词,级别从左到右逐渐升高,最右边的是“顶级域名”。例:com,cn,edu等

域名解析:域名做一个转换,“映射”到真实IP

c、URI/URL

URI:统一资源标识符,能够唯一的标记互联网上资源。(标记互联网资源的一个名字)

URL:统一资源定位符,俗称“网址”,是URI的一个子集

URI三个基本组成部分:协议名(http)+主机名(域名/IP地址)(nginx.org)+路径(资源在主机上的位置,使用/分隔多级目录)

d、HTTPS

HTTPS:运行在SSL/TLS协议上的HTTP

HTTPS = HTTP + SSL/TLS + TCP/IP

SSL/TLS:负责加密通信的安全协议,建立在TCP/IP协议之上

e、代理

代理:HTTP协议里请求方和应答方的中转站,既可以转发客户端的请求,也可以转发服务器的应答。

代理种类:

1、匿名代理:完全隐匿了服务器,只能看到代理服务器

2、透明代理:传输过程透明,既可以知道代理,也可以知道客户端。

3、正向代理:靠近客户端,代替客户端向服务器发送请求。

4、反向代理:靠近服务器端,代替服务器响应客户端请求。

CDN:就是是透明代理和反向代理,代替源站服务器响应客户端请求。

中间层的作用:

1、负载均衡:把访问请求分散到多台机器

2、内容缓存:暂存上下行数据

3、安全防护:隐匿IP

4、数据处理:提供压缩、J加密的功能

三、TCP/IP网络分层

1、TCP/IP网络分层模型

TCP/IP是一个“有层次的协议栈”。HTTP下层协议,负责具体的数据传输工作。

从下往上,4层。

第一层“链接层”:负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标记网络上的设备,所以有时候也叫 MAC层

第二层“网际层”:IP协议所处层。在“链接层”的基础上,用 IP 地址取代MAC 地址,把许许多多的局域网、广域网连接成一个虚拟的巨大网络,在这个网络里找设备时只要把 IP 地址再“翻译”成 MAC 地址就可以了。

第三层“传输层”:保证数据在 IP 地址标记的两点之间“可靠”地传输,是 TCP 协议工作的层次,另外还有它的一个“小伙伴”UDP

TCP和UDP区别:1、 TCP是一个有状态(有脑子)的协议,需要先与对方建立连接然后才能发送数据,2、而且保证数据不丢失不重复;3、TCP 是可以有拥塞控制的,会根据具体情况调整行为;4、TCP 的数据是连续的“字节流”,有先后顺序。

1、UDP 则比较简单,它无状态,不用事先建立连接就可以任意发送数据,2、但不保证数据一定会发到对方;3、UDP 不会根据具体情况调整行为;4、UDP 则是分散的小数据包,是顺序发,乱序收。

第四层“应用层”:有各种面向具体应用的协议。例如 Telnet、SSH、FTP、SMTP 等等,当然还有我们的 HTTP。

MAC 层的传输单位是帧(frame)IP 层的传输单位是包(packet)TCP 层的传输单位是段(segment)HTTP 的传输单位则是消息或报文(message)。但这些名词并没有什么本质的区分,可以统称为数据包

2、OSI分层模型

OSI,全称是“开放式系统互联通信参考模型”。(参考)

OSI 模型分成了七层,从下往上:

1. 第一层:物理层,网络的物理形式,例如电缆、光纤、网卡、集线器等等;
2. 第二层:数据链路层,它基本相当于 TCP/IP 的链接层;
3. 第三层:网络层,相当于 TCP/IP 里的网际层;
4. 第四层:传输层,相当于 TCP/IP 里的传输层;
5. 第五层:会话层,维护网络中的连接状态,即保持会话和同步;
6. 第六层:表示层,把数据转换为合适、可理解的语法和语义;
7. 第七层:应用层,面向具体的应用传输数据

 

OSI优点:1、TCP/IP 是一个纯软件的栈,没有网络应有的最根基的电缆、网卡等物理设备的位置。而 OSI 则补足了这个缺失,在理论层面上描述网络更加完整。

2、OSI 为每一层标记了明确了编号,最底层是一层,最上层是七层,而 TCP/IP 的层次从来只有名字而没有编号。

3、二者映射关系

1. 第一层:物理层,TCP/IP 里无对应;
2. 第二层:数据链路层,对应 TCP/IP 的链接层;
3. 第三层:网络层,对应 TCP/IP 的网际层;
4. 第四层:传输层,对应 TCP/IP 的传输层;
5. 第五、六、七层:统一对应到 TCP/IP 的应用层。

“四层负载均衡”就是指工作在传输层上,基于 TCP/IP 协议的特性,例如 IP 地址、端口号等实现对后端服务器的负载均衡

“七层负载均衡”就是指工作在应用层上,看到的是 HTTP 协议,解析 HTTP 报文里的 URI、主机名、资源类型等数据,再用适当的策略转发给后端服务器

4、TCP/IP协议工作方式

HTTP利用TCP/IP协议传输数据类比发快递

1、HTTP协议里要传输的内容 = 快递

2、自己打包快递 = HTTP 协议为它加一个 HTTP 专用附加数据

3、快递小哥打包快递 = 相当于在 TCP 层给数据再次打包,加上了 TCP 头。

4、快递运到运到集散点运输 = 在 IP 层、MAC 层对 TCP 数据包加上了 IP 头、MAC 头

5、包裹到达目的地快递员的三轮车 = 在 IP层、MAC 层传输后拆包

6、包裹到你家门口撕掉快递包装 = 去除了 TCP 层的头

7、撕掉内包装 =  去除HTTP头

HTTP 协议的传输过程就是这样通过协议栈逐层向下每一层都添加本层的专有数据,层层
打包,然后通过下层发送出去。

接收数据是则是相反的操作,从下往上穿过协议栈,逐层拆包,每层去掉本层的专有头,上
层就会拿到自己的数据。

小结

1. TCP/IP 分为四层,核心是二层的 IP 和三层的 TCP,HTTP 在第四层;
2. OSI 分为七层,基本对应 TCP/IP,TCP 在第四层,HTTP 在第七层;
3. OSI 可以映射到 TCP/IP,但这期间一、五、六层消失了;
4. 日常交流的时候我们通常使用 OSI 模型,用四层、七层等术语;
5. HTTP 利用 TCP/IP 协议栈逐层打包再拆包,实现了数据传输,但下面的细节并不可见。

“两个凡是”:凡是由操作系统负责处理的就是四层或四层以下,否则,凡是需要由应用程序(也就是你自己写代码)负责处理的就是七层

四、域名

1、域名的形式

IP地址替代MAC编号

域名替代IP地址

域名是一个有层次的结构,是一串用“.”分隔的多个单词最右边的被称为“顶级域名”,然后是“二级域名”,层级关系向左依次降低最左边的是主机名,通常用来表明主机的用途

域名本质上还是个名字空间系统,使用多级域名就可以划分出不同的国家、地区、组织、公
司、部门,每个域名都是独一无二的,可以作为一种身份的标识

eg.极客时间的域名“time.geekbang.org”,这里的“org”就是顶级域名“geekbang”是二级域名“time”则是主机名。使用这个域名,DNS 就会把它转换成相应的 IP 地址,你就可以访问极客时间的网站了。

域名的其他用途:
1、在 Apache、Nginx 这样的 Web 服务器里,域名可以用来标识虚拟主机,决定由哪个虚拟
主机来对外提供服务

2、Java 的包机制就采用域名作为命名空间,只是它使用了反序

3、XML 里使用 URI 作为名字空间,也是间接使用了域名

2、域名的解析

DNS = 地址簿

域名解析:IP 地址必须转换成 MAC 地址才能访问主机一样,域名也必须要转换成 IP 地址,这个
过程就是“域名解析

DNS 的核心系统是一个三层的树状、分布式服务,基本对应域名的结构:
1. 根域名服务器(Root DNS Server):管理顶级域名服务器,返
回“com”“net”“cn”等顶级域名服务器的 IP 地址
2. 顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如
com 顶级域名服务器可以返回 apple.com 域名服务器的 IP 地址
3. 权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如
apple.com 权威域名服务器可以返回 www.apple.com 的 IP 地址

任何一个域名都可以在这个树形结构里从顶至下进行查询,就好像是把域名从右到左顺序走了一遍,最终就获得了域名对应的 IP 地址。

在核心 DNS 系统之外,还有两种手段用来减轻域名解析的压力,并且能够更快地获取结果,基本思路就是“缓存”

野生”DNS 服务器(缓存之前的查询结果)、操作系统缓存(缓存之前的查询结果)和 hosts 文件(“主机映射”文件,通常是一个可编辑的文本;操作系统缓存找不到DNS记录,就会找这个文件)后,很多域名解析的工作直接在本地或本机就能解决,不仅方便了用户,也减轻了各级DNS 服务器的压力,效率就大大提升了

 域名解析过程

3、域名的“新玩法”

1、“重定向”:域名代替了 IP 地址,所以可以让对外服务的域名不变,而主机的 IP 地址任意变动。更改 DNS 记录,让域名指向其他的机器。保证业务不中断。
2、使用 bind9 等开源软件搭建一个在内部使用的 DNS,作为名字服务器。开发的各种内部服务就都用域名来标记,比如数据库服务都用域名“mysql.inner.app”,发起网络通信时也就不必再使用写死的 IP 地址了,可以直接用域名

3、基于域名实现的负载均衡
全局负载均衡:域名解析可以返回多个 IP 地址,所以一个域名可以对应多台主机客户端收到多个 IP 地址后,就可以自己使用轮询算法依次向服务器发起请求,实现负载均衡

内部负载均衡:域名解析可以配置内部的策略返回离客户端最近的主机,或者返回当前服务质量最好的主机,这样在 DNS 端把请求分发到不同的服务器,实现负载均衡

恶意DSN:

"域名屏蔽”,对域名直接不解析,返回错误,让你无法拿到 IP 地址,也就无法访问网站;
“域名劫持”,也叫“域名污染”,你要访问 A 网站,但 DNS 给了你 B 网站

4、传统 DNS 存在的问题

1.域名缓存问题

a、没有刷新本地缓存,域名对应的IP地址发生了改变但是不知道。

b、运营商本地服务器缓存静态页面,域名解析时不会指向真正的网站,而是指向缓存的服务器

c、本地缓存使得全局负载均衡失败

2.域名转发问题

a运行商偷懒直接转发请求给b运营商去做解析,b运营商取权威DNS服务器查询时,权威DNS服务器误认为你是b运营商,就会返回一个b运营商的网站地址,每次客户都要跨运营商访问,速度就会很慢。

3.出口 NAT 问题

NAT:网络地址转换

机房都会配置NAT,从这个网关出去的包,都换成新的 IP 地址;一旦做了网络地址的转换,权威的 DNS 服务器,就没办法通过这个地址,来判断客户到底是来自哪个运营商,而且极有可能因为转换过后的地址,误判运营商,导致跨运营商的访问

4.域名更新问题

本地 DNS 服务器是由不同地区、不同运营商独立部署的。有的运营商域名解析缓存的处理更新比较勤快;有的比较懒。

5.解析延迟问题

DNS 的查询过程需要递归遍历多个 DNS 服务器,才能获得最终的解析结果,这会带来一定的时延,甚至会解析超时

5、HTTPDNS 的工作模式

HTTPNDS :不走传统的 DNS 解析,而是自己搭建基于 HTTP 协议的 DNS 服务器集群,分布在多个地点和多个运营商。当客户端需要 DNS 解析的时候,直接通过HTTP 协议进行请求这个服务器集群,得到就近的地址

每家基于 HTTP 协议,自己实现自己的域名解析,自己做一个自己的地址簿,而不使用统一的地址簿。但是默认的域名解析都是走 DNS 的,因而使用 HTTPDNS 需要绕过默认的 DNS 路径,就不能使用默认的客户端。使用 HTTPDNS 的,往往是手机应用,需要在手机端嵌入支持HTTPDNS 的客户端 SDK

HTTPDNS 的工作模式:

a在客户端的 SDK 里动态请求服务端,获取 HTTPDNS 服务器的 IP 列表,缓存到本地。随着不断地解析域名,SDK 也会在本地缓存 DNS 域名解析的结果。

b、当手机应用要访问一个地址的时候,首先看是否有本地的缓存,如果有就直接返回。如果本地没有,就需要请求 HTTPDNS 的服务器,在本地 HTTPDNS 服务器的 IP 列表中,选择一个发出 HTTP 的请求,会返回一个要访问的网站的 IP 列表。

手机客户端自然知道手机在哪个运营商、哪个地址。由于是直接的 HTTP 通信,HTTPDNS服务器能够准确知道这些信息,因而可以做精准的全局负载均衡
 

一是解析速度和更新速度的平衡问题,二是智能调度的问题,对应的解决方案是 HTTPDNS 的缓存设计和调度设计

6、HTTPDNS 的缓存设计

  • 传统DNS存在的问题:

解析 DNS 过程复杂,通信次数多,对解析速度造成很大影响。为了加快解析,因而有了缓存,但是这又会产生缓存更新速度不及时的问题。

  • HTTPDNS解决方案:

1. 解析的过程,不需要本地 DNS 服务递归的调用一大圈,一个 HTTP 的请求直接搞定,要实时更新的时候,马上就能起作用;

2. 为了提高解析速度,本地也有缓存,缓存是在客户端 SDK 维护的,过期时间、更新时间,都可以自己控制。

  HTTPDNS缓存设计策略,分为客户端、缓存、数据源三层。

  • 对于应用架构来讲,就是应用、缓存、数据库。常见的是Tomcat 、Redis、MySQL。
    • 对于HTTPDNS来讲,就是手机客户端、DNS缓存、HTTPDNS服务器

只要是缓存模式,就需要解决缓存的过期、更新、不一致的问题;

SDK中的缓存会严格按照缓存过期时间,如果缓存没有命中,或者已经过期,而且客户端不允许使用过期的记录,则会发起一次解析,保障记录是更新的;

  • 同步解析:
    • 直接调用HTTPDNS的接口,返回最新的记录,更新缓存;
    • 优点:实时性好
    • 缺点:如果有多个请求都发现过期的时候,同时会请求HTTPDNS多次;
    • 更新方式:Cache-Aside机制,先读缓存,不命中读数据库,同时写入缓存;

  • 异步解析:
    • 添加一个解析任务到后台,由后台任务调用HTTPDNS的接口;
    • 优点:可以将多个请求都发现过期的情况,合并为一个对于HTTPDNS的请求任务,只执行一次,减少HTTPDNS的压力。同时创建一个任务进行预加载,防止过期之后刷新;
    • 缺点:当前请求拿到过期数据的时候,如果客户端允许使用过期数据,需要冒一次风险。如果过期的数据还能请求,就没问题;如果不能请求,则失败一次,等下次缓存更新后,再请求方能成功;
    • 更新方式:Refresh-Ahead机制,业务仅仅访问缓存,当过期的时候定期刷新;

7、HTTPDNS 的调度设计

客户端:

客户端中嵌入了SDK,,HTTPDNS服务端可以根据手机是哪个国家、哪个运营商、哪个省,甚至哪个市,选择最佳的服务节点返回;

多个节点还需要考虑虑错误率、请求时间、服务器压力、网络状况等,并非只有地理位置;

客户端还需要具备一定的逃生容错处理能力,例如当出现解析失败的情况下,能回退到传统DNS解析方式进行解析访问;

服务端:

应用可以通过调用HTTPDNS的管理接口,配置不同服务质量的优先级、权重。

    • HTTPDNS会根据这些策略综合地理位置和线路状况算出一个排序,优先访问当前那些优质的、时延低的IP地址。
    • HTTPDNS通过智能调度之后返回的结果,也会缓存在客户端。为了不让缓存使得调度失真,客户端可以根据不同的移动网络运营商WIFI的SSID来分维度缓存。不同的运营商或者WIFI解析出来的结果会不同。

2.4 HttpDNS解决的主要问题

  • Local DNS 劫持:由于 HttpDns 是通过 IP 直接请求 HTTP 获取服务器 A 记录地址,不存在向本地运营商询问 domain 解析过程,所以从根本避免了劫持问题。
  • 平均访问延迟下降:由于是 IP 直接访问省掉了一次 domain 解析过程,通过智能算法排序后找到最快节点进行访问。
  • 用户连接失败率下降:通过算法降低以往失败率过高的服务器排序,通过时间近期访问过的数据提高服务器排序,通过历史访问成功记录提高服务器排序。

2.5 小结

  传统的DNS:解析慢、更新不及时。因为缓存、转发、NAT问题导致客户端误会自己所在的位置和运营商,从而影响流量的调度。

  HTTPDNS通过客户端SDK和服务端,通过HTTP直接调用解析DNS的方式,绕过了传统DNS的这些缺点,实现了智能的调度。

五、动手搭建HTTP实验环境

1、wireshark对握手挥手进行分析

2、wireshark抓包分析步骤

a、运行 www 目录下的“start”批处理程序,启动本机的 OpenResty 服务器

b、启动后可以用“list”批处理确认服务是否正常运行

c、打开 Wireshark,选择“HTTP TCP port(80)”过滤器

d、双击“Npcap loopback Adapter”,开始抓取本机 127.0.0.1 地址上的网络数据。

e、在 Chrome 浏览器的地址栏里输入“http://127.0.0.1/”,再按下回车键,等欢迎页面显示出来后 Wireshark 里就会有捕获的数据包

六、HTTP 协议工作的全过程

1、使用IP地址访问Web服务器抓包分析

 键入网址按下回车后数据传输全过程:

HTTP协议运行在TCP/IP基础上。

1、浏览器要用 HTTP 协议收发数据,首先要做的就是建立 TCP 连接。地址栏里直接输入了 IP 地址“127.0.0.1”,而 Web 服务器的默认端口是80,所以浏览器就要依照 TCP 协议的规范,使用“三次握手”建立与 Web 服务器的连接。
对应Wireshark 里:最开始的三个抓包——SYN、SYN/ACK、ACK

 2、浏览器按照 HTTP 协议规定的格式,通过 TCP 发送了一个“GET / HTTP/1.1”请求报文(第四个包)Web 服务器回复了第五个包,在 TCP 协议层面确认:“刚才的报文我已经收到了”;
3、Web 服务器收到报文后在内部就要处理这个请求。同样也是依据 HTTP 协议的规定,解析报文,看看浏览器发送这个请求想要干什么。要求获取根目录下的默认文件,从磁盘上把那个文件全读出来,再拼成符合 HTTP 格式的报文,发回去(第六个包“HTTP/1.1 200 OK”,底层走的还是 TCP 协议)。浏览器也要给服务器回复一个 TCP 的 ACK 确认,“你的响应报文收到了,多
谢。”,即第七个包

4、浏览器就收到了响应数据解析报文。服务器给我的是个 HTML 文件,好,那我就调用排版引擎、JavaScript 引擎等等处理一下,然后在浏览器窗口里展现出了欢迎页面

 5、浏览器自动请求了作为网站图标的“favicon.ico”文件,与我们输入的网址无关。但因为我们的实验环境没有这个文件,所以服务器在硬盘上找不到,返回了一个“404 Not Found”

6、键入网址再按下回车”的全过程就结束了。

7、TCP 关闭连接的“四次挥手”在抓包里没有出现,这是因为 HTTP/1.1 长连接特性,默认不会立即关闭连接。

最简单的浏览器 HTTP 请求过程:
1. 浏览器从地址栏的输入中获得服务器的 IP 地址和端口号;
2. 浏览器用 TCP 的三次握手与服务器建立连接;
3. 浏览器向服务器发送拼好的报文;
4. 服务器收到报文后处理请求,同样拼好报文再发给浏览器;
5. 浏览器解析报文,渲染输出页面。

2、使用域名访问Web服务器抓包分析

把地址栏的输入改成“http://www.chrono.com”,重复Wireshark 抓包过程,你会发现,好像没有什么不同,浏览器上同样显示出了欢迎界面,抓到的包也同样是 11 个:先是三次握手,然后是两次 HTTP 传输。

浏览器看到了网址里的“www.chrono.com”,发现它不是数字形式的 IP 地址,那就肯定是域名了,于是就会发起域名解析动作,通过访问一系列的域名解析服务器,试图把这个域名翻译成 TCP/IP 协议里的 IP 地址。

具体域名解析过程:在域名解析的过程中会有多级的缓存浏览器首先看一下自己的缓存里有没有,如果没有就向操作系统的缓存要,还没有就检查本机域名解析文件 hosts。

3、真实的网络世界

浏览器判断是不是ip地址,不是就进行域名解析,依次通过浏览器缓存,系统缓存,host文件,还是没找到的请求DNS服务器获取IP解析(解析失败的浏览器尝试换别的DNS服务器,最终失败的进入错误页面),有可能获取到CDN服务器IP地址,访问CDN时先看是否缓存了,缓存了响应用户,无法缓存,缓存失效或者无缓存,回源到服务器。经过防火墙外网网管路由到nginx接入层。ng缓存中存在的直接放回,不存在的负载到web服务器。web服务器接受到请后处理,路径不存在404。存在的返回结果(服务器中也会有redis,ehcache(堆内外缓存),disk等缓存策略)。原路返回,CDN加入缓存响应用户。

小结

1. HTTP 协议基于底层的 TCP/IP 协议,所以必须要用 IP 地址建立连接;
2. 如果不知道 IP 地址,就要用 DNS 协议去解析得到 IP 地址,否则就会连接失败;
3. 建立 TCP 连接后会顺序收发数据,请求方和应答方都必须依据 HTTP 规范构建和解析报文;
4. 为了减少响应时间,整个过程中的每一个环节都会有缓存,能够实现“短路”操作;
5. 虽然现实中的 HTTP 传输过程非常复杂,但理论上仍然可以简化成实验里的“两点”模型

七、HTTP报文是什么样子的?

HTTP 协议的核心部分:传输的报文内容

HTTP 协议在规范文档里详细定义了报文的格式,规定了组成部分,解析规则,还有处理策略,所以可以在 TCP/IP 层之上实现更灵活丰富的功能,例如连接控制,缓存管理、数据编码、内容协商等等。

1、报文结构

TCP/UDP 的报文格式:TCP 报文在实际要传输的数据之前附加了一个 20 字节的头部数据,存储 TCP 协议必须的额外信息,例如发送方的端口号、接收方的端口号、包序号、标志位等等。有了这个附加的 TCP 头,数据包才能够正确传输,到了目的地后把头部去掉,就可以拿到真正的数据。

 HTTP 协议也是与 TCP/UDP 类似,同样也需要在实际传输的数据前附加一些头数据,不过与 TCP/UDP 不同的是,它是一个“纯文本”的协议,所以头数据都是 ASCII 码的文本,可以很容易地用肉眼阅读。

HTTP 协议的请求报文和响应报文的结构基本相同,由三大部分组成:
1. 起始行(start line):描述请求或响应的基本信息
2. 头部字段集合(header):使用 key-value 形式更详细地说明报文
3. 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。

起始行和头部字段经常又合称为“请求头”或“响应头”消息正文又称为“实体”(body)

HTTP 协议规定报文必须有 header,但可以没有 body,而且在 header 之后必须要有一个“空行”,也就是“CRLF”,十六进制的“0D0A”

 浏览器发送 GET 请求的时候都是这样,HTTP 报文经常是只有 header 而没 body。

2、请求行:请求报文的起始行

请求行由三部分构成:
1. 请求方法:是一个动词,如 GET/POST,表示对资源的操作
2. 请求目标:通常是一个 URI,标记了请求方法要操作的资源
3. 版本号:表示报文使用的 HTTP 协议版本。这三个部分通常使用空格(space)来分隔,最后要用CRLF 换行表示结束

GET / HTTP/1.1:“GET”是请求方法,“/”是请求目标,“HTTP/1.1”是版本号。表示“服务器你好,我想获取网站根目录下的默认文件,我用的协议版本号是 1.1,请不要用 1.0 或者 2.0 回复我。”

3、状态行:响应报文的起始行

状态行:服务器响应的状态

状态行由三部分组成:

1. 版本号:表示报文使用的 HTTP 协议版本
2. 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误
3. 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。

HTTP/1.1 200 OK:“浏览器你好,我已经处理完了你的请求,这个报文使用的协议版本号是 1.1,状态码是 200,一切OK。”

“GET /favicon.ico HTTP/1.1”的响应报文状态行HTTP/1.1 404 Not Found:“抱歉啊浏览器,刚才你的请求收到了,但我没找到你要的资源,错误代码是 404,接下来的事情你就看着办吧。”

4、头部字段

请求行或状态行再加上头部字段集合就构成了 HTTP 报文里完整的请求头或响应头

请求头和响应头的结构是基本一样的,唯一的区别是起始行

头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束。比如在“Host: 127.0.0.1”这一行里 key 就是“Host”value就是“127.0.0.1”

HTTP 头字段非常灵活,不仅可以使用标准里的 Host、Connection 等已有头,也可以任意添加自定义头。

使用头字段需要注意:

1. 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;
2. 字段名里不允许出现空格可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;
3. 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格
4. 字段的顺序是没有意义的,可以任意排列不影响语义;
5. 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。

5、常用头字段

HTTP 协议规定了非常多的头部字段,实现各种各样的功能,但基本上可以分为四大类
1. 通用字段:在请求头和响应头里都可以出现;
2. 请求字段仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;
3. 响应字段仅能出现在响应头里,补充说明响应报文的信息;
4. 实体字段:它实际上属于通用字段,但专门描述 body 的额外信息

对 HTTP 报文的解析和处理实际上主要就是对头字段的处理理解了头字段也就理解了 HTTP 报文。

Host字段:请求字段,只能出现在请求头里,它同时也是唯一一个 HTTP/1.1 规范里要求必须出
现的字段
,也就是说,如果请求头里没有 Host,那这就是一个错误的报文。告诉服务器这个请求应该由哪个主机来处理。

User-Agent:请求字段,只出现在请求头里。它使用一个字符串描述发起 HTTP 请求的客户端,服务器可以依据它来返回最合适此浏览器显示的页面

Date:通用字段,但通常出现在响应头里,表示HTTP 报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略。

Server:响应字段,只能出现在响应头里。它告诉客户端当前正在提供 Web 服务的软件名称和版本号,例如在我们的实验环境里它就是“Server: openresty/1.15.8.1”,即使用的是 OpenResty 1.15.8.1。Server 字段也不是必须要出现的。

Content-Length:实体字段,它表示报文里body 的长度,也就是请求头或响应头空行后面数据的长度。服务器看到这个字段,就知道了后续有多少数据,可以直接接收。如果没有这个字段,那么 body 就是不定长的,需要使用 chunked 方式分段传输。

小结

1. HTTP 报文结构就像是“大头儿子”,由“起始行 + 头部 + 空行 + 实体”组成,简单地说就是“header+body”;
2. HTTP 报文可以没有 body,但必须要有 header,而且header 后也必须要有空行,形象地说就是“大头”必须要带着“脖子”;
3. 请求头由“请求行 + 头部字段”构成,响应头由“状态行 + 头部字段”构成;
4. 请求行有三部分:请求方法,请求目标和版本号;
5. 状态行也有三部分:版本号,状态码和原因字符串;
6. 头部字段是 key-value 的形式,用“:”分隔,不区分大小写,顺序任意,除了规定的标准头,也可以任意添加自定义字段,实现功能扩展;
7. HTTP/1.1 里唯一要求必须提供的头字段是 Host,它必须出现在请求头里,标记虚拟主机名。

课后问题:

1:如果拼 HTTP 报文的时候,在头字段后多加了一个CRLF,导致出现了一个空行,会发生什么?

在header 下面第一个空行以后都会被当作body 体

2:讲头字段时说“:”后的空格可以有多个,那为什么绝大多数情况下都只使用一个空格呢?

头字段多一个空格就会多传输一个字节,去掉无用信息,节约资源。

八、理解请求方法

1、标准请求方法

HTTP 协议设计时的定位:要用 HTTP 协议构建一个超链接文档系统,使用 URI 来定位这些文档,也就是资源

请求方法:客户端发出了一个“动作指令”,要求服务器端对 URI 定位的资源执行这个动作

HTTP/1.1 规定了八种方法,单词都必须是大写的形式:

1. GET:获取资源,可以理解为读取或者下载数据;
2. HEAD:获取资源的元信息;
3. POST:向资源提交数据,相当于写入或上传数据;
4. PUT:类似 POST;
5. DELETE:删除资源;
6. CONNECT:建立特殊的连接隧道;
7. OPTIONS:列出可对资源实行的方法;
8. TRACE:追踪请求 - 响应的传输路径。

GET 请求的几种响应方式:

1. 假装这个文件不存在,直接返回一个 404 Not found 报文;
2. 稍微友好一点,明确告诉你有这个文件,但不允许访问,返回一个 403 Forbidden;
3. 再宽松一些,返回 405 Method Not Allowed,然后用Allow 头告诉你可以用 HEAD 方法获取文件的元信息

2、GET/HEAD

GET:请求从服务器获取资源,资源可以是静态的文本、页面、图片、视频,也可以是由 PHP、Java 动态生成的页面或者其他格式的数据

GET 方法搭配 URI其他头字段就能实现对资源更精细的操作:

1、在 URI 后使用“#”,就可以在获取页面后直接定位到某个标签所在的位置

2、使用 If-Modified-Since 字段就变成了“有条件的请求”,仅当资源被修改时才会执行获取动作

3、使用 Range 字段就是“范围请求”,只获取资源的一部分数据
 

HEAD:请求从服务器获取资源;服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”

HEAD用在很多并不真正需要资源的场合,避免传输 body 数据的浪费:

1、检查文件是否存在

2、检查文件是否有最新版本

3、POST/PUT

POST 和 PUT方法是向 URI 指定的资源提交数据,数据就放在报文的 body 里。

只要向服务器发送数据,用的大多数都是 POST:

1、论坛,敲了一堆字后点击“发帖”按钮,浏览器就执行了一次 POST 请求,把你的文字放进报文的body 里,然后拼好 POST 请求头,通过 TCP 协议发给服务器

2、购物网站,点击“加入购物车”,这时也会有 POST 请求,浏览器会把商品 ID发给服务器,服务器再把 ID 写入你的购物车相关的数据库记录

POST 表示的是“新建”“create”的含义,而 PUT(更新) 则是“修改”“update”的含义;实际应用中,PUT 用到的比较少。

4、其他方法

DELETE方法:指示服务器删除资源,通常服务器不会执行真正的删除操作,而是对资源做一个删除标记。更多的时候服务器就直接不处理DELETE请求

CONNECT:要求服务器为客户端和另一台远程服务器建立一条特殊的连接隧道,这时 Web 服务器在中间充当了代理的角色。

OPTIONS方法:要求服务器列出可对资源实行的操作方法,在响应头Allow 字段里返回。

TRACE方法:对 HTTP 链路的测试或诊断,可以显示出请求 - 响应的传输路径存在漏洞,会泄漏网站的信息,所以 Web 服务器通常也是禁止使用。

5、扩展方法

可以任意添加请求动作,只要请求方和响应方都能理解就行。

MKCOL、COPY、MOVE、LOCK、UNLOCK、PATCH

1、用 LOCK 方法锁定资源暂时不允许修改

2、使用 PATCH 方法给资源打个小补丁,部分更新数据。

但因为这些方法是非标准的,所以需要为客户端和服务器编写额外的代码才能添加支持。

6、安全与幂等

安全”:指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改

幂等:多次执行相同的操作,结果也都是相同的,即多次“幂”后结果“相等”

安全的:GET 和 HEAD
幂等的:GET 和 HEAD、DELETE、PUT

DELETE可以多次删除同一个资源,效果都是“资源不存在”。

POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的;而 PUT是“替换或更新数据”,多次更新一个资源,资源还是会第一次更新的状态,所以是幂等的

课后作业:

1. 你能把 GET/POST 等请求方法对应到数据库的“增删改查”操作吗?请求头应该如何设计呢?

答:增:POST 删:DELETE 改:PUT 查:GET
2. 你觉得 TRACE/OPTIONS/CONNECT 方法能够用 GET 或 POST 间接实现吗?

答:自然是可以的,HTTP的POST、GET请求十分的灵活,能组合达到TRACE/OPTIONS/CONNECT等的功能。

九、URI

URI:是统一资源标识符,包含有 URL 和 URN两个部分。

URL:统一资源定位符,网址;常常把这两者简单地视为相等。

1、URI的格式

URI 本质上是一个字符串,这个字符串的作用是唯一地标记资源的位置或者名字。

URI不仅能够标记万维网的资源,也可以标记其他的,如邮件系统、本地文件系统等任意资源。而“资源”既可以是存在磁盘上的静态文本、页面数据,也可以是由 Java、PHP 提供的动态服务

URI 最常用的形式,由 scheme、host:port、path 和 query 四个部分组成,但有的部分可以视情况省略。

2、URI 的基本组成

URI = 协议名 + :// + 主机名:端口号 + 路径(必须以/开头)+ ? + 查询参数

scheme:“方案名”或者“协议名”表示资源应该使用哪种协议来访问(必须有)

最常见的当然就是“http”了,表示使用 HTTP 协议。另外还有“https”,表示使用经过加密、安全的 HTTPS 协议。此外还有其他不是很常见的 scheme,例如 ftp、ldap、file、news 等

应用程序看到 URI 里的 scheme,就知道下一步该怎么走了,会调用相应的 HTTP 或者 HTTPS 下层API

在 scheme 之后,必须是三个特定的字符“://”

authority:表示资源所在的主机名,通常的形式是“host:port”,即主机名加端口号主机名可以是 IP 地址或者域名的形式,必须要有,否则浏览器就会找不到服务器。但端口号有时可以省略,浏览器等客户端会依据 scheme 使用默认的端口号,例如 HTTP 的默认端口号是 80HTTPS 的默认端口号是 443

path 采用了类似文件系统“目录”“路径”的表示方式,path 部分必须以“/”开始,也就是必须包含“/”

file:///D:/http_study/www/:file协议名;/D:/http_study/www/”是路径,而中间的主机名
被“省略”
了。这实际上是 file 类型 URI 的“特例”,它允许省略主机名,默认是本机 localhost。

对于 HTTP 或 HTTPS 这样的网络通信协议,主机名是绝对不能省略的。


HTTP 报文里的 URI“/11-1”与浏览器里输入的“http://www.chrono.com/11-1”有很大的不同,协议名和主机名都不见了,只剩下了后面的部分。因为协议名和主机名已经分别出现在了请求行的版本号和请求头的 Host 字段里,没有必要再重复。当然,在请求行里使用完整的 URI 也是可以的,你可以在课后自己试一下。

客户端和服务器看到的 URI 是不一样的客户端看到的必须是完整的 URI,使用特定的协议去连接特定的主机,而服务器看到的只是报文请求行里被删除了协议名和主机名的 URI

如果你配置过Nginx,你就应该明白了,Nginx 作为一个Web 服务器它的 location、rewrite 等指令操作的 URI其实指的是真正 URI 里的 path 和后续的部分

3、URI的查询参数

使用“协议名 + 主机名 + 路径”的方式,已经可以精确定位网络上的任何资源了。

操作资源的时候附加一些额外的修饰参数

举几个例子:获取商品图片,但想要一个 32×32 的缩略图版本;获取商品列表,但要按某种规则做分页和排序;跳转页面,但想要标记跳转前的原始页面

URI 后面还有一个“query”部分,它在 path之后,用一个“?”开始,但不包含“?”,表示对资源附加的额外要求。

查询参数 query 有一套自己的格式,是多个“key=value”的字符串,这些 KV 值用字符“&”连
浏览器和客户端都可以按照这个格式把长串的查询参数解析成可理解的字典或关联数组形式

4、URI的完整格式

URI 还有一个“真正”的完整形态,如下图所示:

身份信息“user:passwd@”,表示登录主机时的用户名和密码

查询参数后的片段标识符“#fragment”,它是 URI 所定位的资源内部的一个“锚点”或者说是“标签”,浏览器可以在获取资源后直接跳转到它指示的位置

片段标识符仅能由浏览器这样的客户端使用,服务器是看不到的。

5、URI的编码

在 URI 里只能使用 ASCII 码,但如果要在 URI 里使用英语以外的汉语、日语等其他语言该怎么办
呢?

特殊的 URI,会在 path、query 里出现“@&?"等起界定符作用的字符,会导致 URI 解析错误

URI 引入了编码机制对于 ASCII 码以外的字符集和特殊字符做一个特殊的操作,把它们转换成与 URI 语义不冲突的形式。这在 RFC 规范里称为“escape”和“unescape”,俗称“转义”。

URI 转义的规则:直接把非 ASCII 码或特殊字符转换成十六进制字节值,然后前面再加上一个“%”

空格被转义成“%20”,“?”被转义成“%3F”。而中文、日文等则通常使用 UTF-8 编码后再转义

URI可以支持任意的字符集用任何语言来标记资源

课后问题:

1. HTTP 协议允许在在请求行里使用完整的 URI,但为什么浏览器没有这么做呢?

因为在请求头的字段中都有,没必要重复

2. URI 的查询参数和头字段很相似,都是 key-value 形式,都可以任意自定义,那么它们在使用时该如何区别呢?

query参数针对的是资源(uri),而字段针对的是本次请求,也就是报文。一个是长期、稳定的,一个是短期、临时的。

十、响应状态码

响应报文由响应头加响应体数据组成,响应头又由状态行和头字段构成。

状态行的结构,有三部分:

Version 部分是 HTTP 协议的版本号,通常是HTTP/1.1
Reason 部分是原因短语,是状态码的简短文字描述,例如“OK”“Not Found”等等。

状态码是一个十进制数字,以代码的形式表示服务器对请求的处理结果,就像我们通常编写程序时函数返回的错误码一样。

状态码含义:不仅是错误,更重要的意义在于表达HTTP 数据处理的“状态”,客户端可以依据代码适时转换处理状态,例如继续发送请求、切换协议,重定向跳转等,有那么点 TCP 状态转换的意思

1、状态码

状态码是三位数,按照第一位数字分为五类:

1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
2××:成功,报文已经收到并被正确处理;
3××:重定向,资源位置发生变动,需要客户端重新发送请求;
4××:客户端错误,请求报文有误,服务器无法处理;
5××:服务器错误,服务器在处理请求时内部发生了错误

在 HTTP 协议中,正确地理解并应用这些状态码是客户端和服务器双方的责任。客户端作为请求的发起方,获取响应报文后,需要通过状态码知道请求是否被正确处理,才能进行下一步的动作
服务器端作为请求的接收方,在处理请求时,选择最恰当的状态码回复客户端,告知客户端处理的结果指示客户端下一步的行动。

2、1xx

提示信息,是协议处理的中间状态

101 Switching Protocols”:客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了。(很少用)

3、2xx

2××类状态码表示服务器收到并成功处理了客户端的请求

200 OK:最常见,表示一切正常,如果是非 HEAD请求,通常在响应头后都会有 body 数据

“204 No Content”:含义与“200 OK”基本相同,但响应头后没有 body 数据

“206 Partial Content”:HTTP 分块下载或断点续传的基础,在客户端发送“范围请求”、要求获取资源的部分数据时出现,含义与200一样,但 body 里的数据是其中的一部分。伴随着头字段“Content-Range”,表示响应报文里 body 数据的具体范围

4、3xx

3××类状态码表示客户端请求的资源发生了变动,客户端必须用新的 URI 重新发送请求获取资源。

301 Moved Permanently:永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI再次访问

“302 Found”:临时重定向”,意思是请求的资源还在,但需要暂时用另一个 URI 来访问

301 和 302 都会在响应头里使用字段Location指明后续要跳转的 URI浏览器都会重定向到新的URI

两者的区别在于,一个是“永久”,一个是“临时”,所以在场景、用法上差距很大。比如,你的网站升级到了 HTTPS,原来的 HTTP 不打算用了,这就是“永久”的,所以要配置 301 跳转,把所有的HTTP 流量都切换到 HTTPS。网站后台要系统维护服务暂时不可用,就属于“临时”的,可以配置成 302 跳转,把流量临时切换到一个静态通知页面,浏览器看到这个 302 就知道这只是暂时的情况,不会做缓存优化,第二天还会访问原来的地址。

304 Not Modified :用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。它具有通常的跳转含义,但可以理解成“重定向已到缓存的文件”(即“缓存重定向”

5、4xx

4××类状态码表示客户端发送的请求报文有误,服务器无法处理。

400 Bad Request”:通用的错误码表示请求报文有错误,只是一个笼统的错误。所以,在开发 Web 应用时应当尽量避免给客户端返回 400,而是要用其他更有明确含义的状态码。

“403 Forbidden”:实际上不是客户端的请求出错,而是表示服务器禁止访问资源

“404 Not Found”:资源在本服务器上未找到,所以无法提供给客户端。

4××里剩下的一些代码较明确地说明了错误的原因,都很好理解,开发中常用的有:

405 Method Not Allowed:不允许使用某些方法操作资源,例如不允许 POST 只能 GET;
406 Not Acceptable:资源无法满足客户端请求的条件,例如请求中文但只有英文;
408 Request Timeout:请求超时,服务器等待了过长的时间;
409 Conflict:多个请求发生了冲突,可以理解为多线程并发时的竞态;
413 Request Entity Too Large:请求报文里的 body 太大;
414 Request-URI Too Long:请求行里的 URI 太大;
429 Too Many Requests:客户端发送了太多的请求,通常是由于服务器的限连策略;
431 Request Header Fields Too Large:请求头某个字段或总体太大;

6、5xx

5××类状态码表示客户端请求报文正确,但服务器在处理时内部发生了错误,无法返回应有的响应数据,是服务器端的“错误码

500 Internal Server Error:一个通用的错误码

501 Not Implemented:表示客户端请求的功能还不支持

502 Bad Gateway:服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常访问后端服务器时发生了错误,但具体的错误原因也是不知道的。

503 Service Unavailable:表示服务器当前很忙,暂时无法响应服务

小结

1. 状态码在响应报文里表示了服务器对请求的处理结果;
2. 状态码后的原因短语是简单的文字描述,可以自定义;
3. 状态码是十进制的三位数,分为五类,从 100 到 599;
4. 2××类状态码表示成功,常用的有 200、204、206;
5. 3××类状态码表示重定向,常用的有 301、302、304;
6. 4××类状态码表示客户端错误,常用的有 400、403、404;
7. 5××类状态码表示服务器错误,常用的有 500、501、502、503。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值