从输入url到页面展示发生了什么
输入地址
当我们开始在浏览器中输入网址的时候,浏览器其实就已经在智能的匹配可能的url了,他会从历史记录,书签等地方,找到已经输入的字符串可能对应的Url,然后给出智能的提示,让你可以补全地址。对于google的chrome的浏览器,他甚至会直接从缓存中把网页展示出来,就是说,你还没有按下enter,页面就出来了。
浏览器查找域名的IP地址
1.请求一旦发起,浏览器首先要做的事就是解析这个域名,一般来说,浏览器会首先查看本地硬盘的host文件,看看其中有没有和这个域名对应的规则,如果有的话就直接使用Hosts文件里面的ip地址。
2.如果在本地的Hosts文件没有能够找到对应的ip地址,浏览器会发出一个DNS请求到本地DNS服务器。
本地DNS服务器一般都是网络接入服务器商提供,比如中国电信,中国移动.
3.查询你输入的网址的DNS请求到达本地DNS服务器之后,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果,此过程是递归的方式进行查询。如果没有缓存记录,本地DNS服务器还要向DNS根服务器进行查询。
4.根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。这种过程是迭代的过程。(一层一层去找的是递归 | 若找了之后给你信息,让你自已去找的是迭代)。
5.本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的解析服务器的地址。
6.最后,本地DNS服务器向域名的解析服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备这次别的用户查询时,可以直接返回结果,加快网络访问.
知识扩展:
什么是DNS?
DNS(Domain Name System,域名系统),域名和IP地址相互映射的一个分布式数据库,能够使得用户更加方便的访问互联网。而不用去记住那些能被机器读取的IP地址串。通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析。
通俗来说,我们更习惯记住一个网站的名字,比如www.baidu.com而不是记住它的ip地址,比如167.23.10.2,而计算机更擅长记住网站的ip地址,而不是像www.baidu.com等链接。因为DNS就相当于一个电话本,比如你要找www.baidu.com这个域名,那我翻一翻我的电话本,就知道它167.23.10.2
DNS查询的两种方式:
当局部DNS服务器自已不能回答客户机的DNS查询时,它就需要向其他DNS服务器进行查询。此时有两种方式
1.递归方式
局部DNS服务器自已负页向其他DNS服务器进行查询,一般是先向该域名的根域服务器查询,再由根域名服务器一级级向下查询,最后得的查询结果返回给局部DNS服务器,再由局部DNS服务器返回给客户端。
2.迭代方式
当局部DNS服务器自已不能回答客户机的DNS查询时,也可以通过迭代查询的方式进行解析,如图所示,局部DNS服务器不是自已向其他DNS服务器进行查询,而是把解析该域名的其他DNS服务器IP地址返回给客户端DNS程序,客户端DNS程序再继续向这些DNS服务器进行查询,直到查询到结果为止。也就是说迭代的方式只会帮你找到相关的服务器,但是不会帮你去查。比如说:baidu.com的服务器Ip地址在192.168.4.5这里,你自已去查吧.
3.DNS域名称空间的组织方式
4.DNS负载均衡
当一个网站有足够多用户的时候,假如每次请求的资源都位于同一台主机上,那么这台主机随时可能会崩掉。
处理的方案:负载均衡
原理:在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目地。
浏览器向web服务器发送一个HTTP请求
拿到域名对应的IP地址之后,浏览器会以一个随机端口(1024<端口<65535)向服务器的web程序的80端口发送一个TCP的连接请求,这个连接请求到达服务器后,进入网卡,然后进入到TCP/IP协议栈(用于识别该连接,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达WEB程序,最终建立了TCP/IP的连接。
建立了TCP连接之后,发起一个http请求,一个典型的http request header 一般需要包括请求的方法,例如get或post。
客户端向服务器发起http请求时,会有一些请求信息,包含三个部分:
1.请求方法及URL协议/版本
2.请求头(Request Header)
3.请求正文
完整的HTTP请求例子:
GET/sample.jspHTTP/1.1 Accept:image/gif.image/jpey,*/* Accept-Language:zh-cn Connection:Keep-Alive Host:localhost User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0) Accept-Encoding:gzip,defiate username-jinqiao&password=1234
注意:最后一个请求头之后是一个空行,发送回车和换行符,通知服务器以下不再有请求头。
1.请求第一行”方法URL议/版本“:GET/sample.jsp HTTP/1.1
2.请求头(Request Header)
请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等
Accept:image/gif.image/jpey,*/* Accept-Language:zh-cn Connection:Keep-Alive Host:localhost User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0) Accept-Encoding:gzip,defiate
3.请求正文
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来是请求正文。请求正文中可以包含客户提交的查询字符串信息。
username-jinqiao&password=1234
知识扩展:
TCP三次握手
第一次握手:客户端要和服务端进行通信,首先要告知服务端一声,遂发出一个SYN=1的连接请求信号,”服务端,我想给你说说话”。
第二次握手:当服务端接收到客户端的连接请求,此时要给客户端一个确认信息,”我知道了(ACK),我这边已经准备好了,你现在能连吗(SYN)”。
第三次握手:当客户端收到了服务端的确认连接信息后,要礼貌的告知一下服务端,“好的,咱们开始联通吧(ACK)”。
到此整个建立连接的过程已经结束,进入ESTABLISHED状态,接下来就是双方你一句我一句甚至同时交流传递信息的过程了.
为什么需要三次握手?
首先非常明确的是两次握手是最基本的。第一次握手,客户端发了个连接请求消息到服务端,服务端收到信息后知道自己与客户端是可以连接成功的,但此时客户端并不知道服务端是否已经接收到了它的请求,所以服务端接收到消息后的应答,客户端得到服务端的反馈后,才确定自己与服务端是可以连接上的,这就是第二次握手。
客户端只有确定了自己能与服务端连接上才能开始发数据。所以两次握手肯定是最基本的。
看到这里,你或许会问,那么为什么需要第三次握手呢?我们来看一下,假设一下如果没有第三次握手,而是两次握手后我们就认为连接成功了,那么会发生什么?
第三次握手是为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误。
有可能有意外发生:
客户端发出去的第一个连接请求由于某些原因在网络节点中滞留了导致延迟,直到连接释放的某个时间点才到达服务端,这是一个早已失效的报文,但是此时服务端仍然认为这是客户端的建立连接请求第一次握手,于是服务端回应了客户端,第二次握手。
如果只有两次握手,那么到这里,连接就建立了,但是此时客户端并没有任何数据要发送,而服务端还在傻傻的等候佳音,造成很大的资源浪费。所以需要第三次握手,只有客户端再次回应一下,就可以避免这种情况。
TCP四次挥手
第一次挥手:双方交流的差不多了,此时客户端也已经结尾了,接下来要断开通信连接,所以告诉服务端“我说完了(FIN)”,此时自身形成等待结束连接的状态。
第二次挥手:服务端知道客户端已经没话说了,服务端此时还有两句心里话要给客户端说,“我知道你说完了(ACK),我再给你说两句,&*……%¥”。
第三次挥手:此时客户端洗耳恭听继续处于等待结束的状态,服务器端也说完了,自身此时处于等待关闭连接的状态,并对告诉客户端,“我说完了,咱们断了吧(FIN)”。
第四次挥手:客户端收知道服务端也说完了,也要告诉服务端一声(ACK),因为连接和断开要双方都按下关闭操作才能断开,客户端同时又为自己定义一个定时器,因为不知道刚才说的这句话能不能准确到达服务端(网络不稳定或者其他因素引起的网络原因),默认时间定为两个通信的最大时间之和,超出这个时间就默认服务器端已经接收到了自己的确认信息,此时客户端就关闭自身连接,服务器端一旦接收到客户端发来的确定通知就立刻关闭服务器端的连接。
到此为止双方整个通信过程就此终结。这里要声明一下:断开链接不一定就是客户端,谁都可以先发起断开指令,另外客户端和服务端是没有固定标准的,谁先发起请求谁就是客户端。
为什么断开链接的时候客户端设置的定时器时间等待要2MSL(两个通信报文的最大时间)?
这个问题也很好理解,当客户端最终告诉服务器端断开确认的时候,他不知道自己的发出的指令是否能准确的一次性被服务器接收。假如服务器没有接收到(这已经耗费了一个报文的最大通信时间了),服务器端将会重新发起一个结束通话的指令(FIN)到客户端,客户端又接收到了服务器发来的结束通信指令将继续给服务器进行一个确认,有人会说那要是客户端发出的确认信息服务端没收到,而服务端重发的断开指令客户端也没收到怎么办,说实话我也无奈,遇到这种情况咱们干脆认为网确实不行了。
服务器的重定向响应
为什么服务器一定要重定向而不是直接发送用户想看的网页内容呢?其中一个原因跟搜索引擎排名有关。如果一个页面有两个地址,就像http://www.yy.com/和http://yy.com/,搜索引擎会认为它们是两个网站,结果造成每个搜索链接都减少从而降低排名。而搜索引擎知道301永久重定向是什么意思,这样就会把访问带www的和不带www的地址归到同一个网站排名下。还有就是用不同的地址会造成缓存友好性变差,当一个页面有好几个名字时,它可能会在缓存里出现好几次。
扩展知识
301和302的区别
301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。
他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;
302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301
重定向的原因
1.网站调整(如改变网页目录结构);
2.网页被移到一个新地址;
3.网页扩展名改变(如应用需要把.php改成.Html或.shtml)。
这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。
什么时候进行301或者302跳转呢?
当一个网站或者网页24—48小时内临时移动到一个新的位置,这时候就要进行302跳转,而使用301跳转的场景就是之前的网站因为某种原因需要移除掉,然后要到新的地址访问,是永久性的。
清晰明确而言:使用301跳转的大概场景如下:
1、域名到期不想续费(或者发现了更适合网站的域名),想换个域名。
2、在搜索引擎的搜索结果中出现了不带www的域名,而带www的域名却没有收录,这个时候可以用301重定向来告诉搜索引擎我们目标的域名是哪一个。
3、空间服务器不稳定,换空间的时候。
浏览器跟踪重定向地址
现在浏览器知道了 "http://www.google.com/"才是要访问的正确地址,所以它会发送另一个http请求
服务器处理请求
经过前面的步骤,我们终于将我们的http请求发送到了服务器这里,其实前面的重定向已经是到达服务器了,那么服务器是如何处理我们的请求的。
后端从在固定的端口接收到TCP报文开始,它会对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。
一些大一点的网站,会将你的请求到反向代理服务器中,因为当网站访问量非常大,网站就越来越慢,一台服务器就不够用了,于是将同一个应用部署在多台服务器上,将大量用户的请求分配给多台机器处理。此时,客户端不是直接通过HTTP协议访问某网站应用服务器。同时也带来了一个好处,其中一台服务器挂了,只要还有其他服务器正常运行,就不会影响用户使用。
如图:
通过Nginx的反向代理,我们到达了web服务器,服务端脚本处理我们的请求,访问我们的数据库,获取需要获取的内容。
扩展阅读:
什么是反向代理?
客户端本来可以直接通过HTTP协议访问某网站应用服务器,网站管理员可以在中间加上一个Nginx,客户端请求Nginx,Nginx请求应用服务器,然后将结果返回给客户端,此时Nginx就是反向代理服务器。
服务器返回一个HTTP响应
经过前面的步骤,服务器收到了我们的请求,也处理我们的请求,到这一步,它会把它的处理结果返回,也就是返回一个HTPP响应。
HTTP响应与HTTP请求相似,HTTP响应也由3个部分构成,分别是:
-状态行
状态行由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
格式: HTTP-Version Status-Code Reason-Phrase CRLF
例如: HTTP/1.1 200 OK rn
状态码
1xx:信息性状态码,表示服务器已接收了客户端请求,客户端可继续发送请求。 100 Continue 101 Switching Protocols 2xx:成功状态码,表示服务器已成功接收到请求并进行处理。 200 OK 表示客户端请求成功 204 No Content 成功,但不返回任何实体的主体部分 206 Partial Content 成功执行了一个范围(Range)请求 3xx:重定向状态码,表示服务器要求客户端重定向。 301 Moved Permanently 永久性重定向,响应报文的Location首部应该有该资源的新URL 302 Found 临时性重定向,响应报文的Location首部给出的URL用来临时定位资源 303 See Other 请求的资源存在着另一个URI,客户端应使用GET方法定向获取请求的资源 304 Not Modified 服务器内容没有更新,可以直接读取浏览器缓存 307 Temporary Redirect 临时重定向。与302 Found含义一样。302禁止POST变换为GET,但实际使用时并不一定,307则更多浏览器可能会遵循这一标准,但也依赖于浏览器具体实现 4xx:客户端错误状态码,表示客户端的请求有非法内容。 400 Bad Request 表示客户端请求有语法错误,不能被服务器所理解 401 Unauthonzed 表示请求未经授权,该状态代码必须与 WWW-Authenticate 报头域一起使用 403 Forbidden 表示服务器收到请求,但是拒绝提供服务,通常会在响应正文中给出不提供服务的原因 404 Not Found 请求的资源不存在,例如,输入了错误的URL 5xx:服务器错误状态码,表示服务器未能正常处理客户端的请求而出现意外错误。 500 Internel Server Error 表示服务器发生不可预期的错误,导致无法完成客户端的请求 503 Service Unavailable 表示服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常
-响应头(Response Header)
由关键字/值对组成,每行一对,关键字和值用英文冒号":"分隔,典型的响应头有:
响应正文
包含着我们需要的一些具体信息,比如cookie,html,image,后端返回的请求数据等等。这里需要注意,响应正文和响应头之间有一行空格,表示响应头的信息到空格为止.
HTTP/1.1 200 OK Date: Sat, 31 Dec 2005 23:59:59 GMT Content-Type: text/html;charset=ISO-8859-1 Content-Length: 122 <html> <head> <title>http</title> </head> <body> <!-- body goes here --> </body> </html>
浏览器显示HTML
可查看我的上一篇文章《浏览器渲染原理》.
格外备注:当文档加载过程中遇到js文件,html文档会挂起渲染(加载解析渲染同步)的线程,不仅要等待文档中js文件加载完毕,还要等待解析执行完毕,才可以恢复html文档的渲染线程。因为JS有可能会修改DOM,最为经典的document.write,这意味着,在JS执行完成前,后续所有资源的下载可能是没有必要的,这是js阻塞后续资源下载的根本原因。所以我明平时的代码中,js是放在html文档末尾的。
浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS)
其实这个步骤可以并列在步骤8中,在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签。这时,浏览器会发送一个获取请求来重新获得这些文件。比如我要获取外图片,CSS,JS文件等,类似于下面的链接:
图片:http://static.ak.fbcdn.net/rs...
CSS式样表:http://static.ak.fbcdn.net/rs...
JavaScript 文件:http://static.ak.fbcdn.net/rs...
这些地址都要经历一个和HTML读取类似的过程。所以浏览器会在DNS中查找这些域名,发送请求,重定向等等...
不像动态页面,静态文件会允许浏览器对其进行缓存。有的文件可能会不需要与服务器通讯,而从缓存中直接读取,或者可以放到CDN中