基础
网络:
- 二层转发:设备工作在链路层,帧在经过交换机设备时,检查帧的头部信息,拿到目标 mac 地址,进行本地转发和广播
- 三层路由:设备工作在网络(ip)层,报文经过有路由功能的设备时,设备分析报文中的头部信息,拿到 ip 地址,根据网段范围,进行本地转发或选择下一个网关
- dns,网络请求的第一步是域名解析,所以工作在应用层
域名
DNS 的核心系统是一个三层的树状 、分布式服务,基本对应域名的结构:
根域名服务器(Root DNS Server):管理顶级域名服务器,返回“com”“net”“cn”等顶级域名服务器的 IP 地址;
顶级域名服务器(Top-level DNS Server):管理各自域名下的权威域名服务器,比如 com 顶级域名服务器可以返回 apple.com
域名服务器的 IP 地址;
权威域名服务器(Authoritative DNS Server):管理自己域名下主机的 IP 地址,比如 apple.com
权威域名服务器可以返回 www.apple.com
的 IP 地址。
任何一个域名都可以在这个树形结构里从顶至下进行查询,就好像是把域名从右到左顺序走了一遍,最终就获得了域名对应的 IP 地址。
例如,你要访问 www.apple.com
,就要进行下面的三次查询:
访问根域名服务器,它会告诉你 com
顶级域名服务器的地址;
访问“com”顶级域名服务器,它再告诉你 apple.com
域名服务器的地址;
最后访问 apple.com
域名服务器,就得到了 www.apple.com
的地址。
- 知名的 DNS 有 Google 的“8.8.8.8”,Microsoft 的“4.2.2.1”,还有 CloudFlare 的“1.1.1.1”等等
总结:
域名使用字符串来代替 IP 地址,方便用户记忆,本质上一个名字空间系统; DNS 就像是我们现实世界里的电话本、查号台,统管着互联网世界里的所有网站,是一个“超级大管家”; DNS 是一个树状的分布式查询系统,但为了提高查询效率,外围有多级的缓存; 使用 DNS 可以实现基于域名的负载均衡,既可以在内网,也可以在外网。
键入网址再按下回车,后面究竟发生了什么?
简要叙述一下这次最简单的浏览器 HTTP 请求过程:
浏览器从地址栏的输入中获得服务器的 IP 地址和端口号; 浏览器用 TCP 的三次握手与服务器建立连接; 浏览器向服务器发送拼好的报文; 服务器收到报文后处理请求,同样拼好报文再发给浏览器; 浏览器解析报文,渲染输出页面。
HTTP 报文是什么样
请求行
了解了 HTTP 报文的基本结构后,我们来看看请求报文里的起始行也就是请求行(request line),它简要地描述了客户端想要如何操作服务器端的资源。
请求行由三部分构成:
- 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
- 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
- 版本号:表示报文使用的 HTTP 协议版本。
这三个部分通常使用空格(space)来分隔,最后要用 CRLF 换行表示结束。
GET /get/user HTTP/1.1
状态行
看完了请求行,我们再看响应报文里的起始行,在这里它不叫“响应行”,而是叫“状态行”(status line),意思是服务器响应的状 态。
比起请求行来说,状态行要简单一些,同样也是由三部分构成:
- 版本号:表示报文使用的 HTTP 协议版本;
- 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
- 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
HTTP/1.1 200 OK
头部字段
头字段需要注意下面几点:
- 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;
- 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;
- 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;
- 字段的顺序是没有意义的,可以任意排列不影响语义;
- 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie。
HTTP 协议规定了非常多的头部字段,实现各种各样的功能,但基本上可以分为四大类:
- 通用字段:在请求头和响应头里都可以出现;
- 请求字段:仅能出现在请求头里,进一步说明请求信息或者额外的附加条件;
- 响应字段:仅能出现在响应头里,补充说明响应报文的信息;
- 实体字段:它实际上属于通用字段,但专门描述 body 的额外信息。
- Host 字段,它属于请求字段,只能出现在请求头里,它同时也是唯一一个 HTTP/1.1 规范里要求必须出现的字段,也就是说,如果请求头里没有 Host,那这就是一个错误的报文。
- Date 字段是一个通用字段,但通常出现在响应头里,表示 HTTP 报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略。
- Server 字段是响应字段,只能出现在响应头里。
如果头字段后多了一个 CRLF,会被当做 body 处理;头字段时说“:”后的空格可以有多个,绝大多数情况下都只使用一个空格是为了节省资源。
如何理解请求方法?
目前 HTTP/1.1 规定了八种方法,单词都必须是大写的形式,我先简单地列把它们列出来,后面再详细讲解。(前四个是比较常用的)
- GET:获取资源,可以理解为读取或者下载数据;
- HEAD:获取资源的元信息;请求资源的头部信息, 并且这些头部与 HTTP GET 方法请求时返回的一致,不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”. 该请求方法的一个使用场景是在 下载一个大文件前先获取其大小再决定是否要下载, 以此可以节约带宽资源;检查一个文件是否存在;检查文件是否有最新版本
- POST:向资源提交数据,相当于写入或上传数据;
- PUT:类似 POST;用于新增资源或者使用请求中的有效负载替换目标资源的表现形式
- DELETE:用于删除指定的资源;
- CONNECT:建立特殊的连接隧道;HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器
- OPTIONS:列出可对资源实行的方法;用于获取目的资源所支持的通信选项
- TRACE:追踪请求 - 响应的传输路径。回显服务器 收到的请求,主要用于测试或诊断;它的本意是好的,但存在漏洞,会泄漏网站的信息,所以 Web 服务器通常也是禁止使用
扩展方法:例如 MKCOL、COPY、MOVE、LOCK、UNLOCK、PATCH 等
PATCH: 用于对资源进行部分修改; LOCK 方法锁定资源暂时不允许修改
安全与幂等
安全与幂等。所谓的“安全”是指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改。
按照这个定义,只有 GET 和 HEAD 方法是“安全”的,因为它们是“只读”操作,只要服务器不故意曲解请求方法的处理方式,无论 GET 和 HEAD 操作多少次,服务器上的数据都是“安全的”。
而 POST/PUT/DELETE 操作会修改服务器上的资源,增加或删除数据,所以是“不安全”的。
所谓的“幂等”实际上是一个数学用语,被借用到了 HTTP 协议里,意思是多次执行相同的操作,结果也都是相同的,即多次“幂”后结果“相等”。
很显然,GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等的。 POST 和 PUT 的幂等性质就略费解一点。POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的;而 PUT 是“替换或更新数据”,多次更新一个资源,资源还是会第一次更新的状态,所以是幂等的。
网址
- URI:也就是统一资源标识符(Uniform Resource Identifier)
- URL:统一 资源定位符(Uniform Resource Locator)
- URN:统一资源名称(Uniform Resource Name) URI 不完全等同于网址,它包含有 URL 和 URN 两个部分。
URI 最常用的形式:由 scheme、host:port、path 和 query 四个部分组成,
URI 最常用的形式,由四个部分组成部分可以视情况省略:
scheme://host:port/path?query=
- scheme:叫“方案名”或者“协议名”,表示资源应该使用哪种协议来访问。常见的 HTTP、经过加密、安全的 HTTPS 协议。此外还有其他不是很常见:ftp、ldap、file、news
- host:port:在”://”之后,是被称为“authority”的部分,表示资源所在的主机名,通常的形式是“host:port”,即主机名加端口号。HTTP 的默认端口号是 80,HTTPS 的默认端口号是 443。
- path:标记资源所在位置的路径
- query:请求查询参数,格式为多个“key=value”的字符串,这些 KV 值用字符“&”拼接。
采用了 UNIX 的“/”风格
https://test.xxx.com/get/user?userid=1&name=test
file:///C:/work/test/
URI 还有一个“真正”的完整形态 scheme
://
user:passwd@
host:port
path
?query
#fragment
- 协议名之后、主机名之前的身份信息“user:passwd@”,表示登录主机时的用户名和密码,但现在已经不推荐使用这种形式了(RFC7230),因为它把敏感信息以明文形式暴露出来,存在严重的安全隐患。
- 查询参数后的片段标识符“#fragment”,它是 URI 所定位的资源内部的一个“锚点”或者说是“标签”,浏览器可以在获取资源后直接跳转到它指示的位置。仅由浏览器客户端使用,浏览器不会把带“#fragment”的 URI 发送给服务器,服务器也不会处理。
在 URI 里对“@&/”等特殊字符和汉字必须要做编码,否则服务器收到 HTTP 报文后会无法正确处理。URI 引入了编码机制,对于 ASCII 码以外的字符集和特殊字符会把它们转换成与 URI 语义不冲突的形式。这在 RFC 规范里称为“escape”和“unescape”,俗称“转义”。
URI 转义的规则为把非 ASCII 码或特殊字符转换成十六进制字节值,然后前面再加上一个“%”。例如:空格被转义成“%20”,“?”被转义成“%3F”。而中文、日文等则通常使用 UTF-8 编码后再转义,例如“银河”会被转义成“%E9%93%B6%E6%B2%B3”。不过我们在浏览器的地址栏里通常不会看到转义后的“乱码”的,实际上是浏览器一种“友好”表现,隐藏了 URI 编码后的“丑陋一面”。从地址栏,把它再拷贝到其他的编辑器里,如果有转义 的字符它就会展示为转义后的字符。
响应状态码
五类的具体含义是:
- 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
- 101 Switching Protocols”。它的意思是客户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了。
- 2xx:成功,报文已经收到并被正确处理;
- 200 OK,表示从客户端发来的请求在服务器端被正确处理
- 201 Created 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立
- 202 Accepted 请求已接受,但是还没执行,不保证完成请求
- 204 No content,表示请求成功,但响应报文不含实体的主体部分
- 206 Partial Content,进行范围请求。是 HTTP 分块下载或断点续传的基础,服务器成功处理了请求,但 body 里的数据不是资源的全部,而是其中的一部分。通常伴随着头字段“Content-Range”,表示响应报文里 body 数据的具体范围,供客户端确认,例如“Content-Range: bytes 0-99/2000”,意思是此次获取的是总计 2000 个字节的前 100 个字节。
- 3xx:重定向,资源位置发生变动,需要客户端重新发送请求;
- 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL
- 302 found,临时性重定向,表示资源临时被分配了新的 URL
- 303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源
- 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况。用于缓存控制。
- 307 temporary redirect,临时重定向,和 302 含义相同
- 308 Permanent Redirect 永久重定向
- 4xx:客户端错误,请求报文有误,服务器无法处理;
- 400 bad request,请求报文存在语法错误
- 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息
- 403 forbidden,表示对请求资源的访问被服务器拒绝
- 404 not found,表示在服务器上没有找到请求的资源
- 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:请求头某个字段或总体太大;
- 5xx:服务器错误,服务器在处理请求时内部发生了错误
- 500 internal sever error,表示服务器端在执行请求时发生了错误
- 501 Not Implemented 请求超出服务器能力范围,例如服务器不支持当前请求所需要的某个功能,或者请求是服务 器不支持的某个方法
- 503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求 。是一个“临时”的状态,响应报文里通常还会有一个“Retry-After”字段,指示客户端可以在多久以后再次尝试发送请求。
- 505 http version not supported 服务器不支持 ,或者拒绝支持在请求中使用的 HTTP 版本
HTTP 有哪些特点
- 灵活可扩展:HTTP 协议是一个“灵活可扩展”的传输协议,可以任意添加头字段实现任意功能。在发展过程不断添加新功能和特性;
- 可靠传输:HTTP 协议是一个“可靠”的传输协议,基于 TCP/IP 协议“尽量”保证数据的送达。因为 HTTP 协议是基于 TCP/IP 的,从而继承 TCP 的“可靠”的特性,能够在请求方和应答方之间“可靠”地传输数据。它的具体做法与 TCP/UDP 差不多,都是对实际传输的数据(entity)做了一层包装,加上一个头,然后调用 Socket API,通过 TCP/IP 协议栈发送或者接收;
- 应用层协议:HTTP 协议是一个应用层的协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据;
- 请求-应答:HTTP 协议使用的是请求-应答通信模式,客户端主动发起请求,服务器被动回复请求。是 HTTP 协议最根本的通信模型,通俗来讲就是“一发一收”。该模式也完全符合 RPC(Remote Procedure Call)的工作模式,可以把 HTTP 请求处理封装成远程函数调用,导致了 WebService、RESTful 和 gPRC 等的出现;
- 无状态:HTTP 协议是无状态的,每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。 HTTP 是有连接无状态,顺序发包顺序收包,按照收发的顺序管理报文;
- 其他特点:除了以上的五大特点,其他例如传输的实体数据可缓存可压缩、可分段获取数据、支持身份认证、支持国际化语言等。这些并不能算是 HTTP 的基本特点,因为这都是由第一个“灵活 可扩展”的特点所衍生出来的。
http1.0 是“无连接”的每次请求应答后都会关闭,http1.1 后默认开启 keep-alive 长连接机制,所以 HTTP 以不再是“无连接”了。
灵活可扩张是最大优点,可靠性比不上 MQ(保证 100% 收发成功使用消息中间件),传输数据虽然通用,可是文件传输时效率肯定比不是 FTP,无状态,在需要状态的地方通过扩展弥补不足。请求应答,有些需要服务器主动推得需要用 websocket 协议。
HTTP 有哪些优点?又有哪些缺点
- HTTP 最大的优点是简单、灵活和易于扩展;
- HTTP 拥有成熟的软硬件环境,应用的非常广泛,是互联网的基础设施;
- HTTP 是无状态的,可以轻松实现集群化,扩展性能,但有时也需要用 Cookie 技术来实现“有状态”;
- HTTP 是明文传输,数据完全肉眼可见,能够方便地研究分析,但也容易被窃听;
- HTTP 是不安全的,无法验证通信双方的身份,也不能判断报文是否被窜改;
- HTTP 的性能不算差,但不完全适应现在的互联网,还有很大的提升空间。