Nivelle 开拓视野冲破艰险看见世界 身临其境贴近彼此感受生活

一次完整的http请求

2017-06-10
nivelle

域名解析

  • 浏览器首先会搜素自身的DNS缓存(缓存时间比较短,大概只有1分钟,且只能容纳1000条缓存),查看自身的缓存是否有域名对应的条目,如果没有过期,则解析到此结束.
  • 如果没有找到对应的条目,那么浏览器会搜索操作系统自身的DNS缓存,如果找到且没有过期则解析到此结束
  • 如果在windows系统的DNS缓存也没有找到,那么尝试读取host文件(位于C:\Windows\System32\drivers\etc),如果这里有则解析成功
  • 如果在hosts文件中也没有找到对应的条目,浏览器会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器(一般是电信运营商提供的,也可以使用像Google提供的DNS服务器)发起域名解析请求(通过udp协议向DNS的53端口发起请求,这个请求是递归请求,也就是运营商必须提供给我们该域名的Ip地址),运营商的DNS服务器首先会查找自身的缓存,找到对应的条目,且没有过期,则解析成功.如果没有找到对应的条目,则有运营商的DNS代我们的浏览器发起迭代DNS解析请求,它首先会找根域的DNS的IP地址(DNS服务器都内置13台根域的DNS IP地址),找到根域的DNS地址,就会向其发起请求(我请求的域www.baidu.com名ip地址是多少呀),根域发现这是一个顶级域com域的一个域名,于是就告诉运行商的DNS我不知道这个域名的IP地址,我知道com域的IP地址,去找它,于是运营商找到了com域的IP地址,又向com域的IP地址发起请求(我请求的域名www.baidu.comip地址是多少呀) ,com这台服务器告诉运营商的DNS我不知道这个域名的IP地址,但是我知道baidu.com这个域的DNS地址,你去找它去,于是运营商的DNS又向baidu.com这个域名的DNS地址(这个一般就是由域名注册商提供的)发起请求(www.baidu.com这个域名的IP地址是多少),这个时候查询到baidu.com域的DNS服务器查询到www.baidu.com域名对应的IP地址,于是就把找到的结果返回给运营商的DNS服务器,这个时候运行的服务器就拿到了域名对应的IP地址,并返回给windows系统内核,内核又把结果返回给浏览器,终于拿到了www.baidu.com对应的IP地址.

TCP三次握手

拿到域名对应的IP地址之后,User-Agent(一般是指浏览器)会以一个随机端口(1024<端口< 65535)向服务器的web程序(通常有httpd,nginx)的80端口发起TCP的连接请求.这个连接请求(原始的http请求经过TCP/IP 4层模型的层层包装)到达服务器端后(这中间通过各种路由设备,局域网除外),进入到网卡,然后是进入到内核的TCP/IP协议(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过netfilter防火墙(属于内核的模块)的过滤,最终达到web程序 ,最终建立起TCP/IP的连接.

image

首先Client端发送连接请求报文,Server段接收到连接后回复ACK报文,并为这次连接分配资源.Client端收到ACK报文后也向Server段发送ACK报文,并分配资源,这样TCP连接就建立了.

(1) ACK=0 表示确认号无效,SYN = 1 表示这是一个连接请求或连接接受报文,同时表示这个数据报不能携带数据,seq = x 表示Client自己的初始序号(seq = 0 就代表这是第0号包),这时候Client进入syn_sent状态,表示客户端等待服务器的回复

(2)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的确认。

(3) Client收到确认后还需再次发送确认,同时携带要发送给Server的数据。ACK 置1 表示确认号ack= y + 1 有效(代表期望收到服务器的第1个包),Client自己的序号seq= x + 1(表示这就是我的第1个包,相对于第0个包来说的),一旦收到Client的确认之后,这个TCP连接就进入Established状态,就可以发起http请求了。

image


假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说”我Client端没有数据要发给你了”,但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,”告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息”。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,”告诉Client端,好了,我这边数据发完了,准备好关闭连接了”。Client端收到FIN报文后,”就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,”就知道可以断开连接了”。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!


image

image

为什么连接的时候是三次握手,关闭的时候却是四次握手?

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。

建立TCP连接后发起Http请求

进过TCP3次握手之后,浏览器发起了http的请求(看第包),使用的http的方法 GET 方法,请求的URL是 / ,协议是HTTP/1.0

HTTP请求报文和响应报文格式:

起始行: 如 GET/HTTP/1.0 (请求的方法 请求的URL 请求所使用的协议)

头部信息:User-Agent Host等成对出现的值

主体

不管是请求报文还是响应报文都会遵循以上的格式。

请求的协议有哪些种类:

http/0.9: stateless

http/1.0: MIME, keep-alive (保持连接), 缓存

http/1.1: 更多的请求方法,更精细的缓存控制,持久连接(persistent connection) 比较常用


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

服务器响应http请求,返回html代码

服务器端WEB程序接收到http请求以后,就开始处理该请求,处理之后就返回给浏览器html文件。

1xx: 信息性状态码

100, 101

2xx: 成功状态码

200:OK

3xx: 重定向状态码

301: 永久重定向, Location响应首部的值仍为当前URL,因此为隐藏重定向;

302: 临时重定向,显式重定向, Location响应首部的值为新的URL

304:Not Modified  未修改,比如本地缓存的资源文件和服务器上比较时,发现并没有修改,服务器返回一个304状态码,

                    告诉浏览器,你不用请求该资源,直接使用本地的资源即可。

4xx: 客户端错误状态码

404: Not Found  请求的URL资源并不存在

5xx: 服务器端错误状态码

500: Internal Server Error  服务器内部错误

502: Bad Gateway  前面代理服务器联系不到后端的服务器时出现

504:Gateway Timeout  这个是代理能联系到后端的服务器,但是后端的服务器在规定的时间内没有给代理服务器

浏览器解析html代码(并请求资源文件)

浏览器拿到index.html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(会使用多线程下载,每个浏览器的线程数不一样),这个时候就用上keep-alive特性了,建立一次HTTP连接,可以请求多个资源,下载资源的顺序就是按照代码里的顺序,但是由于每个资源大小不一样,而浏览器用多线程请求请求资源,所以从下图看出,这里显示的顺序并不一定是代码里面的顺序。

浏览器在请求静态资源时(在未过期的情况下),向服务器端发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码(告诉浏览器服务器端没有修改),那么浏览器会直接读取本地的该资源的缓存文件。

详细的浏览器工作原理:https://kb.cnblogs.com/page/129756/

浏览器对html进行渲染

最后,浏览器利用自己内部的工作机制,把请求到的静态资源和html代码进行渲染,渲染之后呈现给用户。

转载至http://blog.51cto.com/linux5588/1351007


下一篇 重构技巧

评论