本文由 简悦 SimpRead 转码, 原文地址 www.jianshu.com
最近,终于要把《WEB 请求处理系列》提上日程了,一直答应小伙伴们给分享一套完整的 WEB 请求处理流程:从浏览器、Nginx、Servlet 容器,最终到应用程序 WEB 请求的一个处理流程,前段时间由于其他工作事情的安排,一直未进行整理。不过还好该系列终于启动了,给大家分享的同时,也顺便整理下自己的思路,以便温故而知新吧。希望大家都能在此过程中得到新的收获吧。
本系列主要分五部分:
1.《WEB 请求处理一:浏览器请求发起处理》:分析用户在浏览器中输入 URL 地址,浏览器如何找到服务器地址的过程,并发起请求;
2.《WEB 请求处理二:Nginx 请求反向代理》:分析请求在达反向代理服务器内部处理过程;
3.《WEB 请求处理三:Servlet 容器请求处理》:分析请求在 Servlet 容器内部处理过程,并找到目标应用程序;
4.《WEB 请求处理四:WEB MVC 框架请求处理》:分析请求在应用程序内部,开源 MVC 框架的处理过程;
5.《WEB 请求处理五:浏览器请求响应处理》:分析请求在服务器端处理完成后,浏览器渲染响应页面过程;
为直观明了,先上一张图,红色部分为本章所述模块:
1 B/S 网络架构概述
我们先了解下 B/S 网络架构是什么?B/S 网络架构从前端到后端都得到了简化,**_都基于统一的应用层协议HTTP来交互数据,HTTP协议采用无状态的短链接的通信方式_**
,通常情况下,一次请求就完成了一次数据交互,通常也对应一个业务逻辑,然后这次通信连接就断开了。采用这种方式是为了能够同时服务更多的用户,**_因为当前互联网应用每天都会处理上亿的用户请求,不可能每个用户访问一次后就一直保持住这个连接_**
。
当一个用户在浏览器里输入 www.google.com 这个 URL 时,将会发生如下操作:
- 首先,浏览器会请求 DNS 把这个域名解析成对应的 IP 地址;
- 然后,根据这个 IP 地址在互联网上找到对应的服务器,建立 Socket 连接,向这个服务器发起一个 HTTP Get 请求,由这个服务器决定返回默认的数据资源给访问的用户;
- 在服务器端实际上还有复杂的业务逻辑:服务器可能有多台,到底指定哪台服务器处理请求,这需要一个负载均衡设备来平均分配所有用户的请求;
- 还有请求的数据是存储在分布式缓存里还是一个静态文件中,或是在数据库里;
- 当数据返回浏览器时,浏览器解析数据发现还有一些静态资源(如:css,js 或者图片)时又会发起另外的 HTTP 请求,而这些请求可能会在 CDN 上,那么 CDN 服务器又会处理这个用户的请求;
以上具体流程,如图所示:
不管网络架构如何变化,但是始终有一些固定不变的原则需要遵守:
- 互联网上所有资源都要用一个 URL 来表示。URL 就是统一资源定位符;
- 必须基于 HTTP 协议与服务端交互;
- 数据展示必须在浏览器中进行;
2 HTTP 协议解析
**_B/S网络架构的核心是HTTP协议,最重要的就是要熟悉HTTP协议中的HTTP Header_**
,HTTP Header 控制着互联网上成千上万的用户的数据传输。最关键的是,**_它控制着用户浏览器的渲染行为和服务器的执行逻辑_**
。
常见的 HTTP 请求头:
常见的 HTTP 响应头:
常见的 HTTP 状态码:
2.1 浏览器缓存机制
当我们使用 Ctrl+F5 组合键刷新一个页面时,**_首先是在浏览器端,会直接向目标URL发送请求,而不会使用浏览器缓存的数据;其次即使请求发送到服务端,也有可能访问到的是缓存的数据_**
。所以在 HTTP 的请求头中会增加一些请求头,它告诉服务端我们要获取最新的数据而非缓存。**_最重要的是在请求Head中增加了两个请求项Pragma:no-cache和Cache-Control:no-cache_**
。
- Cache-Control/Pragma
这个 HTTP Head 字段**_用于指定所有缓存机制在整个请求/响应链中必须服从的指令,如果知道该页面是否为缓存,不仅可以控制浏览器,还可以控制和HTTP协议相关的缓存或代理服务器_**
。
Cache-Control/Pragma 字段的可选值:
Cache-Control 请求字段被各个浏览器支持的较好,**_而且它的优先级也比较高_**
,它和其他一些请求字段(如 Expires)同时出现时,**_Cache-Control会覆盖其他字段_**
。
**_Pragma字段的作用和Cache-Control有点类似_**
,它也是在 HTTP 头中包含一个特殊的指令,使相关的服务器来遵守,**_最常用的就是Pragma:no-cache,它和Cache-Control:no-cache的作用是一样的_**
。
- Expires 缓存过期时间
**_Expires通常的使用格式是Expires:Sat,25 Feb 2012 12:22:17 GMT_**
,后面跟着一个日期和时间,**_超过这个值后,缓存的内容将失效_**
,也就是**_浏览器在发出请求之前检查这个页面的这个字段,看该页面是否已经过期了,过期了将重新向服务器发起请求_**
。
- Last-Modified/Etag 最后修改时间
**_Last-Modified字段一般用于表示一个服务器上的字段的最后修改时间_**
,资源可以是静态(静态内容自动加上 Last-Modified)或者动态的内容(如 Servlet 提供了一个 getLastModified 方法用于检查某个动态内容是否已经更新),**_通过这个最后修改时间可以判断当前请求的资源是否是最新的_**
。
一般服务器端在响应头中返回一个 Last-Modified 字段,告诉浏览器这个页面的最后修改时间,如:Sat,25 Feb 2012 12:55:04 GMT,**_浏览器再次请求时在请求头中增加一个If-Modified-Since:Sat,25 Feb 2012 12:55:04 GMT字段_**
,询问当前缓存的页面是否是最新的,**如果是最新的就会返回304状态码**
,告诉浏览器是最新的,服务器也不会传输新的数据。
与 Last-Modified 字段有类似功能的还有一个 Etag 字段,**_这个字段的作用是让服务端给每个页面分配一个唯一编号,然后通过这个编号来区分当前这个页面是否是最新的_**
。这种方式比使用 Last-Modified 更加灵活,但是在后端的 Web 服务器有多台时比较难处理,**_因为每个Web服务器都要记住网站的所有资源编号,否则浏览器返回这个编号就没有意义了_**
。
3 WEB 工作流程
对于正常的上网过程,系统其实是这样做的:
浏览器本身是一个客户端,当你输入 URL 的时候,
**_首先浏览器会去请求DNS服务器,通过DNS获取相应的域名对应的IP_**
,然后通过 IP 地址找到 IP 对应的服务器后,**_要求建立TCP连接,等浏览器发送完HTTP Request(请求)包后_**
,服务器接收到请求包之后才开始处理请求包,服务器调用自身服务,返回 HTTP Response(响应)包;客户端收到来自服务器的响应后开始渲染这个 Response 包里的主体(body),等收到全部的内容随后断开与该服务器之间的 TCP 连接。
Web 请求的工作原理可以简单地归纳为:
- 浏览器通过 DNS 域名解析到服务器 IP;
- 客户机通过 TCP/IP 协议建立到服务器的 TCP 连接;
- 客户端向服务器发送 HTTP 协议请求包,请求服务器里的资源文档;
- 服务器向客户机发送 HTTP 协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理 “动态内容”,并将处理得到的数据返回给客户端;
- 客户机与服务器断开。由客户端解释 HTML 文档,在客户端屏幕上渲染图形结果;
一个简单的 HTTP 事务就是这样实现的,看起来很复杂,原理其实是挺简单的。**_需要注意的是客户机与服务器之间的通信是非持久连接的_**
,也就是当服务器发送了应答后就与客户机断开连接,等待下一次请求。
4 DNS 域名解析
4.1 DNS 域名解析过程
当用户在浏览器中输入域名,如:www.google.com,并按下回车后,DNS 解析过程大体如下:
- 浏览器缓存检查(本机)
**_浏览器会首先搜索浏览器自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),看自身的缓存中是否有www.google.com对应的条目,而且没有过期,如果有且没有过期则解析到此结束_**
。
浏览器缓存域名也是有限制的,不仅浏览器缓存大小有限制,而且缓存的时间也有限制,通常情况下为几分钟到几小时不等,**_域名被缓存的时间限制可以通过TTL属性来设置_**
。这个缓存时间太长和太短都不好,如果缓存时间太长,一旦域名被解析到的 IP 有变化,会导致被客户端缓存的域名无法解析到变化后的 IP 地址,以致该域名不能正常解析,这段时间内有可能会有一部分用户无法访问网站。如果时间设置太短,会导致用户每次访问网站都要重新解析一次域名。
注:我们怎么查看 Chrome 自身的缓存?可以使用 chrome://net-internals/#dns 来进行查看
- 操作系统缓存检查(本机)+hosts 解析(本机)
如果浏览器自身的缓存里面没有找到对应的条目,**_其实操作系统也会有一个域名解析的过程,那么Chrome会首先搜索操作系统自身的DNS缓存中是否有这个域名对应的DNS解析结果,如果找到且没有过期则停止搜索解析到此结束_**
。
**_其次在Linux中可以通过/etc/hosts文件来设置,你可以将任何域名解析到任何能够访问的IP地址_**
。如果你在这里指定了一个域名对应的 IP 地址,那么浏览器会首先使用这个 IP 地址。**_当解析到这个配置文件中的某个域名时,操作系统会在缓存中缓存这个解析结果_**
,缓存的时间同样是受这个域名的失效时间和缓存的空间大小控制的。
- 本地区域名服务器解析(LDNS)
如果在 hosts 文件中也没有找到对应的条目,**_浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器_**
(LDNS 一般是电信运营商提供的,也可以使用像 Google 提供的 DNS 服务器)发起域名解析请求(通过的是 UDP 协议向 DNS 的 53 端口发起请求,这个请求是递归的请求,也就是运营商的 DNS 服务器必须得提供给我们该域名的 IP 地址)。
在我们的网络配置中都会有 “DNS 服务器地址” 这一项,**_这个地址就用于解决前面所说的如果两个过程无法解析时要怎么办,操作系统会把这个域名发送给这里设置的LDNS,也就是本地区的域名服务器_**
。**_这个DNS通常都提供给你本地互联网接入的一个DNS解析服务_**
,例如你是在学校接入互联网,那么你的 DNS 服务器肯定在你的学校,如果你是在一个小区接入互联网的,那这个 DNS 就是提供给你接入互联网的应用提供商,即电信或者联通,也就是通常所说的 SPA,那么这个 DNS 通常也会在你所在城市的某个角落,通常不会很远。**_这个专门的域名解析服务器性能都会很好,它们一般都会缓存域名解析结果,当然缓存时间是受域名的失效时间控制的,一般缓存空间不是影响域名失效的主要因素_**
。大约 80% 的域名解析都到这里就已经完成了,所以 LDNS 主要承担了域名的解析工作。
**_运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。_**
- 根域名服务器解析(Root Server)
如果 LDNS 没有找到对应的条目,**_则由运营商的DNS代我们的浏览器发起迭代DNS解析请求_**
。它首先是会找根域的 DNS 的 IP 地址(这个 DNS 服务器都内置 13 台根域的 DNS 的 IP 地址),**_找到根域的DNS地址,就会向其发起请求_**
(请问 www.google.com 这个域名的 IP 地址是多少啊?)。
- 根域名服务器返回给本地域名服务器一个所查询域的主域名服务器 (gTLD Server) 地址,gTLD 是国际顶级域名服务器,如. com、.cn、.org 等,全球只有 13 台左右。
根域发现这是一个顶级域 com 域的一个域名,**_于是就告诉运营商的DNS我不知道这个域名的IP地址,但是我知道com域的IP地址_**
,你去找它去。
- 本地域名服务器 (Local DNS Server) 再向上一步返回的 gTLD 服务器发送请求。
于是运营商的 DNS 就得到了 com 域的 IP 地址,又向 com 域的 IP 地址发起了请求(请问 www.google.com 这个域名的 IP 地址是多少?),**_com域这台服务器告诉运营商的DNS我不知道www.google.com这个域名的IP地址,但是我知道google.com这个域的DNS地址_**
,你去找它去。
- 接受请求的 gTLD 服务器查找并返回此域名对应的 Name Server 域名服务器的地址,这个 Name Server 通常就是你注册的域名服务器,例如你在某个域名服务提供商申请的域名,那么这个域名解析任务就由这个域名提供商的服务器来完成。
于是运营商的 DNS 又向 google.com 这个域名的 DNS 地址(**_这个一般就是由域名注册商提供的,像万网,新网等_**
)发起请求(请问 www.google.com 这个域名的 IP 地址是多少?),**_这个时候google.com域的DNS服务器一查,果真在我这里,于是就把找到的结果发送给运营商的DNS服务器,这个时候运营商的DNS服务器就拿到了www.google.com这个域名对应的IP地址_**
。
- Name Server 域名服务器会查询存储的域名和 IP 的映射关系表,正常情况下都根据域名得到目标 IP 记录,连同一个 TTL 值返回给 DNS Server 域名服务器。
- 返回该域名对应的 IP 和 TTL 值,Local DNS Server 会缓存这个域名和 IP 的对应关系,缓存的时间由 TTL 值控制。
- 把解析的结果返回给用户,用户根据 TTL 值缓存在本地系统缓存中,域名解析过程结束。
通过上面的步骤,我们最后获取的是 IP 地址,也就是浏览器最后发起请求的时候是基于 IP 来和服务器做信息交互的。在实际的 DNS 解析过程中,可能还不止这 10 个步骤,**_如Name Server也可能有多级,或者有一个GTM来负载均衡控制_**
,这都有可能会影响域名解析的过程。根据以上解析流程,**_DNS解析整个过程,分为:递归查询过程和迭代查询过程_**
。如图所示:
**所谓 递归查询过程 就是 “查询的递交者” 更替, 而 迭代查询过程 则是 “查询的递交者”不变。**
举个例子来说,你想知道某个一起上法律课的女孩的电话,并且你偷偷拍了她的照片,回到寝室告诉一个很仗义的哥们儿,这个哥们儿二话没说,拍着胸脯告诉你,甭急,我替你查 (
**此处完成了一次递归查询,即,问询者的角色更替**
)。然后他拿着照片问了学院大四学长,学长告诉他,这姑娘是 xx 系的;然后这哥们儿马不停蹄又问了 xx 系的办公室主任助理同学,助理同学说是 xx 系 yy 班的,然后很仗义的哥们儿去 xx 系 yy 班的班长那里取到了该女孩儿电话。(**此处完成若干次迭代查询,即,问询者角色不变,但反复更替问询对象**
) 最后,他把号码交到了你手里。完成整个查询过程。
4.2 跟踪域名解析过程
在 Linux 系统中还可以**_使用dig命名来查询DNS的解析过程,如下所示:dig +cmd +trace www.google.com_**
**_上面清楚地显示了整个域名是如何发起和解析的,从根域名(.)到gTLD Server(.com.)再到Name Server (google.com.)的整个过程都显示出来了_**
。还可以看出 DNS 的服务器有多个备份,可以从任何一台查询到解析结果。
4.3 清除缓存的域名
我们知道 DNS 域名解析后会缓存解析结果,其中主要在两个地方缓存结果,**_一个是Local DNS Server,另外一个是用户的本地机器。这两个缓存都是TTL值和本机缓存大小控制的,但是最大缓存时间是TTL值,基本上Local DNS Server的缓存时间就是TTL控制的,很难人工介入_**
,但是我们的本机缓存可以通过如下方式清除。
在 Linux 下可以通过 / etc/init.d/nscd restart 来清除 DNS 缓存。如下:
JVM 缓存 DNS 解析结果:
在 Java 应用中 JVM 也会缓存 DNS 的解析结果,**_这个缓存是在InetAddress类中完成的_**
,而且这个缓存时间还比较特殊,它有两种缓存策略:**_一种是正确解析结果缓存,另一种是失败的解析结果缓存_**
。这两个缓存时间由两个配置项控制,配置项是在 %JAVA HOME%\lib\security\java.security 文件中配置的。**两个配置项分别是networkaddress.cache.ttl 和networkaddress.cache.negative.ttl,它们的默认值分别是-1(永不失效)和10(缓存10秒)
_**。
**要修改这两个值同样有几种方式**
,分别是:直接修改 java.security 文件中的默认值、在 Java 的启动参数中增加 - Dsun.net.inetaddr.ttl=xxx 来修改默认值、通过 InetAddress 类动态修改。
在这里还要特别强调一下,**_如果我们需要用InetAddress类解析域名时,一定要是单例模式_**
,不然会有严重的性能问题,如果每次都创建 InetAddress 实例,每次都要进行一次完整的域名解析,非常耗时,这点要特别注意。
4.4 几种域名解析方式
- A 记录,A 代表的是 Address,用来指定域名对应的 IP 地址
如将 item.taobao.com 指定到 115.238.23.241,将 switch.taobao.com 指定到 121.14.24.241。**_A记录可以将多个域名解析到一个IP地址,但是不能将一个域名解析到多个IP地址_**
。
- MX 记录,表示的是 Mail Exchange,就是可以将某个域名下的邮件服务器指向自己的 Mail Server
如 taobao.com 域名的 A 记录 IP 地址是 115.238.25.245,如果 MX 记录设置为 115.238.25.246,是 xxx@taobao.com 的邮件路由,**_DNS会将邮件发送到115.238.25.246所在的服务器,而正常通过Web请求的话仍然解析到A记录的IP地址_**
。
- CNAME 记录,全称是 Canonical Name(别名解析),所谓的别名解析就是可以为一个域名设置一个或者多个别名
如将 taobao.com 解析到 xulingbo.net,将 srcfan.com 也解析到 xulingbo.net,**_其中xulingbo.net分别是taobao.com和srcfan.com的别名_**
。前面的跟踪域名解析中的 “www.taobao.com. 1542 IN CNAME www.gslb.taobao.com” 就是 CNAME 解析。
- NS 记录,为某个域名指定 DNS 解析服务器,也就是这个域名有指定的 IP 地址的 DNS 服务器去解析
前面的 “google.com. 172800 IN NS ns4.google.com.” 就是 NS 解析。
- TXT 记录,为某个主机名或域名设置说明
如可以为 google.com 设置 TXT 记录为 “谷歌 | 中国” 这样的说明。
4.5 网络抓包分析
Linux 虚拟机测试,**_使用命令 wget www.linux178.com 来请求_**
,发现直接使用 chrome 浏览器请求时,干扰请求比较多,所以就使用 wget 命令来请求,**_不过使用wget命令只能把index.html请求回来,并不会对index.html中包含的静态资源(js、css等文件)进行请求_**
。
抓包截图如下:
1 号包,这个是那台虚拟机在广播,要获取 192.168.100.254(也就是网关)的 MAC 地址,
**_因为局域网的通信靠的是MAC地址,它为什么需要跟网关进行通信是因为我们的DNS服务器IP是外围IP,要出去必须要依靠网关帮我们出去才行_**
。2 号包,这个是网关收到了虚拟机的广播之后,
**_回应给虚拟机的回应,告诉虚拟机自己的MAC地址_**
,于是客户端找到了路由出口。3 号包,这个包是 wget 命令向系统配置的 DNS 服务器提出域名解析请求(准确的说应该是 wget 发起了一个 DNS 解析的系统调用),请求的域名 www.linux178.com,
**_期望得到的是IP6的地址(AAAA代表的是IPv6地址)_**
。4 号包,这个 DNS 服务器给系统的响应,很显然目前使用 IPv6 的还是极少数,所以得不到 AAAA 记录的。
5&6 号包,这个还是请求解析 IPv6 地址,但是 www.linux178.com.leo.com 这个主机名是不存在的,所以得到结果就是 no such name。
7 号包,这个才是请求的域名对应的 IPv4 地址(A 记录)。
8 号包,
**_DNS服务器不管是从缓存里面,还是进行迭代查询最终得到了域名的IP地址,响应给了系统,系统再给了wget命令,wget于是得到了www.linux178.com的IP地址_**
,这里也可以**_看出客户端和本地的DNS服务器是递归的查询(也就是服务器必须给客户端一个结果)这就可以开始下一步了_**
,进行 TCP 的三次握手。
5 发起 TCP 的 3 次握手
拿到域名对应的 IP 地址之后,**_User-Agent(一般是指浏览器)会以一个随机端口(1024 < 端口 < 65535)向服务器的WEB程序(常用的有httpd,nginx等)80端口发起TCP的连接请求。_**
这个连接请求(原始的 http 请求经过 TCP/IP4 层模型的层层封包)到达服务器端后(这中间通过各种路由设备,局域网内除外),进入到网卡,然后是进入到内核的 TCP/IP 协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过 Netfilter 防火墙(属于内核的模块)的过滤,最终到达 WEB 程序,最终建立了 TCP/IP 的连接。
如下图所示:
- Client 首先发送一个连接试探,ACK=0 表示确认号无效,SYN = 1 表示这是一个连接请求或连接接受报文,同时表示这个数据报不能携带数据,seq = x 表示 Client 自己的初始序号(seq = 0 就代表这是第 0 号包),这时候 Client 进入 syn_sent 状态,表示客户端等待服务器的回复。
- Server 监听到连接请求报文后,如同意建立连接,则向 Client 发送确认。TCP 报文首部中的 SYN 和 ACK 都置 1 ,ack = x + 1 表示期望收到对方下一个报文段的第一个数据字节序号是 x+1,同时表明 x 为止的所有数据都已正确收到(ack=1 其实是 ack=0+1, 也就是期望客户端的第 1 个包),seq = y 表示 Server 自己的初始序号(seq=0 就代表这是服务器这边发出的第 0 号包)。这时服务器进入 syn_rcvd,表示服务器已经收到 Client 的连接请求,等待 client 的确认。
- Client 收到确认后还需再次发送确认,同时携带要发送给 Server 的数据。ACK 置 1 表示确认号 ack= y + 1 有效(代表期望收到服务器的第 1 个包),Client 自己的序号 seq= x + 1(表示这就是我的第 1 个包,相对于第 0 个包来说的),一旦收到 Client 的确认之后,这个 TCP 连接就进入 Established 状态,就可以发起 http 请求了。
看抓包截图:
TCP 为什么需要 3 次握手?
举个例子:假设一个老外在故宫里面迷路了,看到了小明,于是就有下面的对话:
老外: Excuse me,Can you Speak English?
小明: yes 。
老外: OK,I want …
在问路之前,老外先问小明是否会说英语,小明回答是的,这时老外才开始问路。
2 个计算机通信是靠协议(目前流行的 TCP/IP 协议)来实现, 如果 2 个计算机使用的协议不一样,那是不能进行通信的,**_所以这个3次握手就相当于试探一下对方是否遵循TCP/IP协议,协商完成后就可以进行通信了_**
,当然这样理解不是那么准确。
为什么 HTTP 协议要基于 TCP 来实现?
目前在 Internet 中所有的传输都是通过 TCP/IP 进行的,**_HTTP协议作为TCP/IP模型中应用层的协议也不例外,TCP是一个端到端的可靠的面向连接的协议_**
,所以 HTTP 基于传输层 TCP 协议不用担心数据的传输的各种问题。
6 建立 TCP 连接后发起 http 请求
**_经过TCP3次握手之后,浏览器发起了http的请求(看第⑫包)_**
,使用的 http 的方法 GET 方法,请求的 URL 是 / , 协议是 HTTP/1.0:
下面是第 12 号包的详细内容:
以上的报文是 HTTP 请求报文。那么 HTTP 请求报文和响应报文会是什么格式呢?
起始行:如 GET / HTTP/1.0 (请求的方法 请求的 URL 请求所使用的协议)
头部信息:User-Agent Host 等成对出现的值
主体
不管是请求报文还是响应报文都会遵循以上的格式。那么起始行中的请求方法有哪些种呢?
GET: 完整请求一个资源 (常用)
HEAD: 仅请求响应首部
POST: 提交表单 (常用)
PUT: 上传
DELETE: 删除
OPTIONS: 返回请求的资源所支持的方法的方法
TRACE: 追求一个资源请求中间所经过的代理
那什么是 URL、URI、URN?
URI Uniform Resource Identifier 统一资源标识符,如:scheme://[username:password@]HOST:port/path/to/source
URL Uniform Resource Locator 统一资源定位符,如:http://www.magedu.com/downloads/nginx-1.5.tar.gz
URN Uniform Resource Name 统一资源名称
**_URL和URN都属于URI_**
,为了方便就把 URL 和 URI 暂时都通指一个东西。
请求的协议有哪些种?有以下几种:
http/0.9: stateless
http/1.0: MIME, keep-alive (保持连接), 缓存
http/1.1: 更多的请求方法,更精细的缓存控制,持久连接 (persistent connection) 比较常用
下面是 Chrome 发起的 http 请求报文头部信息:
Accept 就是告诉服务器端,接受那些 MIME 类型
Accept-Encoding 这个看起来是接受那些压缩方式的文件
Accept-Lanague 告诉服务器能够发送哪些语言
Connection 告诉服务器支持 keep-alive 特性,TCP 连接在发送后将仍然保持打开状态,于是,
**_浏览器可以继续通过相同的TCP连接发送请求_**
。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。Cookie 每次请求时都会携带上 Cookie 以方便服务器端识别是否是同一个客户端
Host 用来标识请求服务器上的那个虚拟主机,比如 Nginx 里面可以定义很多个虚拟主机,那这里就是用来标识要访问那个虚拟主机。
User-Agent 用户代理,一般情况是浏览器,也有其他类型,如:wget curl 搜索引擎的蜘蛛等
条件请求头部:If-Modified-Since 是浏览器向服务器端询问某个资源文件如果自从什么时间修改过,那么重新发给我,这样就保证服务器端资源文件更新时,浏览器再次去请求,而不是使用缓存中的文件。
安全请求头部:Authorization: 客户端提供给服务器的认证信息;
什么是 MIME?
MIME(Multipurpose Internet Mail Extesions 多用途互联网邮件扩展)是一个互联网标准,它扩展了电子邮件标准,使其能够支持非 ASCII 字符、二进制格式附件等多种格式的邮件消息,这个标准被定义在 RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049 等 RFC 中。 由 RFC 822 转变而来的 RFC 2822,规定电子邮件标准并不允许在邮件消息中使用 7 位 ASCII 字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息都不能在电子邮件中传输。
**_MIME规定了用于表示各种各样的数据类型的符号化方法。_**
此外,在万维网中使用的 HTTP 协议中也使用了 MIME 的框架,标准被扩展为互联网媒体类型。
MIME 遵循以下格式:**major/minor 主类型/次类型**
例如:
image/jpg
image/gif
text/html
video/quicktime
appliation/x-httpd-php