【知识详解】从输入网址后发生了什么
输入网址后发生了什么
1. DNS域名解析
从我们是输入的URL到获得目的ip地址的过程,这是一个递归查询的过程。
首先应该查询缓存,依次查找浏览器DNS缓存-->本地系统DNS缓存-->本地计算机host文件-->ISP的DNS缓存-->递归搜索。
递归搜索的顺序:根域名服务器-->com顶级域名服务器-->google.com域名服务器
所以网址的真正解析过程:.-->.com-->google.com-->www.google.com.
2. 建立TCP连接(三次握手)
各参数意义:
序列号seq:表示发送的数据序号x;
确认号ack:期望收到的下一个数据信号x+1;
同步标志位SYN: SYN=1表示是一个连接请求或连接接受;
确认标志位ACK: ACK=1表示确认号字段有效;
终止标志位FIN: FIN=1表示发送完毕,要求释放连接;
SYN连接建立报文
ACK应答报文
FIN连接释放报文
客户机发SYN消息-->服务器使用SYN+ACK表示收到了这个消息-->客户机再以ACK响应
- 第一次握手:SYN=1,seq=x,进入SYN-SENT状态,等待确认;
- 第二次握手:SYN=1, ACK=1, seq=y, ack=x+1(确认对方的,发送自己),进入SYN-RECV状态;
- 第三次握手:ACK=1, seq=x+1, ack=y+1(确认对方,发送自己),客户端服务器进入ESTABLISHED状态;
问:为什么是三次握手?
本质上是为了在不可靠的信道建立可靠的连接,防止已经失效的报文突然又到了服务器,假设客户端发送了一个请求连接,但是因为信道的原因发生了滞留,等了一会没有收到确认,再次发送请求连接,这次信道情况较好,很快进行了确认接受了连接,但是过了一会那个滞留的连接到达服务器,其实已经是一个失效的报文了,服务器以为客户端再次发起新的连接,回复确认。如果采用两次握手,服务器发出确认后就建立了连接,但是客户端并没有发出连接的请求,所以不会理睬服务器的确认,那这样服务器认为连接已经建立,一直等待客户端发送数据,造成资源的浪费。如果是三次握手的话,服务器会等着客户端的确认,如果收不到确认,就知道客户端并没有想建立连接。
3. 发送http请求
https过程:HTTPS在传输数据之前需要客户端与服务器进行一个握手(TLS/SSL握手),在握手过程中将确立双方加密传输数据的密码信息。TLS/SSL使用了非对称加密,对称加密以及hash等。具体可参考:Https详解。
HTTPS相比于HTTP,虽然提供了安全保证,但是势必会带来一些时间上的损耗,如握手和加密等过程,是否使用HTTPS需要根据具体情况在安全和性能方面做出权衡。
Http过程
发送http请求就是构建http报文并通过TCP协议发送到服务器指定端口(http:80,https:443),报文由3部分组成:请求行,请求头,请求体
请求行
Method Request-URL HTTP-Version CRLF
eg: GET index.html HTTP/1.1
方法有get、post、put、delete
URL:统一资源定位符;
组成:组成:<协议>://<主机>:<端口>/<路径> 注:端口和路径有时可以省略(HTTP默认端口号是80)
比如:https://localhost:8080/index.html?key1=value1&keys2=value2
问:get和post有什么区别?
1、在没有参数时两者的请求行中只有method不同;在带参数时,get请求的数据会附在URL之后(放在请求行),以?分割,多个参数用&连接,而post请求会放在请求体中,比如,如果参数是:name=xin, age=22
get方法的报文:
GET /index.php?name=xin&age=22 HTTP/1.1
Host: localhost
post方法的报文
POST /index.php HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
name=xin&age=22
2、从URL来看post请求比get请求要安全,因为参数信息不会显示在地址栏上,但从传输上来看两者都是不安全的,因为都是用的http,在网络上上是明文传输,随时都可能被抓包获取。
3、get方法在浏览器地址栏上输入的参数是有限的,这并不是http协议的限制,而是浏览器和服务器的限制。而post请求请求体并没有长度限制。所以get请求传输数据较少,post请求能传输大量数据。
4、get主要用于信息获取。不会增加或修改资源,只是查询。post主要用于更新资源信息。
5、get方法产生一个TCP数据包,浏览器会把请求头和请求体一并发出去,服务器响应200 ok。post方法产生两个TCP数据包,浏览器会先把请求头发给服务器,返回100 continue,再发请求体,返回200 ok。
它们的本质都是 TCP 链接,并无区别。但是由于 HTTP 的规定以及浏览器/服务器的限制,导致它们在应用过程中可能会有所不同。
4. 服务器处理请求并返回HTTP报文
后端从固定的端口收到TCP报文后,这一部分对应编程语言的socket,它会对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用,这一部分工作由Web服务器进行,比如Tomcat。
HTTP响应报文也由3部分组成:状态码,响应头,响应体;
状态码
状态码就是服务器告诉客户端,发送了什么事;
问:常见状态码?
1**:指示信息--表示请求已接收,继续处理;
2**:成功--表示请求已被成功接收、理解、接受
200 OK 服务器成功处理了请求
3**:重定向--要完成请求必须更进一步的操作
301/302 Moved Permanently 请求的URL已移走,Response中应该包含一个Location URL, 说明资源现在所处的位置
4**:客户端错误--请求有语法错误或请求无法实现
404 Not Found 未找到资源
5**:服务端错误--服务器未能实现合法的请求(自己出错了或网站都挂了)
501 Internal Server Error服务器遇到一个错误,使其无法为请求提供服务
响应头
响应体
服务器返回给浏览器的信息,比如html、css、js等。
5. 浏览器解析渲染页面
浏览器解析HTML文件构建DOM树,每个标签都是一个节点;
解析CSS文件构建渲染树。这是一个很复杂的过程。
6. 释放TCP连接(四次挥手)
- 1.客户端发出连接释放报文,停止发送数据,FIN=1,seq=u(等于前面传过来的最后一个序列号+1,TCP规定FIN报文段即使不携带数据,也消耗一个序号),此时客户端进入FIN-WAIT-1(终止等待1)状态。
- 2.服务器收到连接释放报文,发出报文确认,ACK=1,ack=u+1,并且带上自己的序列号,seq=v,此时服务器进入CLOSE-WAIT状态,这时候客户端不发了,但是服务端还要发,客户端依然要接收。客户端收到确认请求后,进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文。
- 3.服务器发送完毕后,向客户端发送连接释放报文,FIN=1,ACK=1,ack=u+1,seq=w,此时,服务器进入LAST-WAIT(最后确认)状态,等待客户端确认。
- 4.客户端收到连接释放报文,发出报文确认,ACK=1,ack=w+1,自己的序列号仍是seq=u+1,此时,客户端进入TIME-WAIT(时间等待)状态,注意此时TCP连接没有释放,必须等待2MSL(最长报文段寿命)时间后,才会进入CLOSE(关闭)状态。服务器只要收到了确认后,立马进入CLOSED状态。所以服务器结束时间要比客户端早一些。
问:为什么握手是三次而挥手是四次?
因为服务器收到客户端的SYN连接建立报文后,可以直接发送SYN+ACK报文,即应答和同步,但是在关闭连接时,服务器可能还有数据要发送,所以只回复一个应答告诉客户端自己收到了,但是我这不能关,得等我发完了,我才能发送FIN连接释放报文。
问:为什么TIME-WAIT需要2MSL才能返回CLOSE状态?
因为信道是不可靠的,最后一个ACK确认报文发送后可能会丢失,服务器如果没有收到ACK确认,就会重发FIN连接释放报文,如果客户端又收到了,那就知道刚才那个确认丢失了,重发ACK确认。所以,当客户端在2MSL时间内没有再次收到FIN报文后,客户端就知道服务器已经成功收到了,进入CLOSED状态。