在建立HTTP请求之前需要做哪些准备工作呢?
在建立HTTP请求之前主要有两部分工作:DNS解析和通信链路的建立。简单说就是,首先发起请求的客户端浏览器要明确知道所要访问的服务器地址,然后建立通往该服务器地址的路径。
DNS解析
DNS解析过程是通过查询将URL中的Host字段转化为网络中具体的IP地址,因为域名只是为了方便记忆,IP地址才是所访问服务器在网络中的“门牌号”。
DNS解析过程:
首先查询浏览器自身的DNS缓存,如果查到IP地址就结束解析,由于缓存时间限制比较大,一般只有1分钟,同时缓存容量也有限制,所以在浏览器缓存中没找到IP地址时,就会搜索系统自身的DNS缓存;如果还未找到,接着就会尝试从系统的hosts文件中查找。
在本地主机进行的查询若都没获取到,接下来便会在 本地域名服务器 上查询。如果本地域名服务器没有直接的目标IP地址可供返回,则本地域名服务器便会采取迭代的方式去依次查询 根域名服务器、COM顶级域名服务器 和 权限域名服务器 等,最终将所要访问的目标服务器IP地址返回本地主机,若查询不到,则返回报错信息。
由此可以看出DNS解析是个很耗时的过程,若解析的域名过多,势必会延缓首屏的加载时间。
网络模型
通过DNS解析获取到目标服务器IP地址后,就可以建立网络连接进行资源的请求与响应了。
在此之前,我们需要对网络架构模型有一些基本的认识。
在互联网发展初期,为了使网络通信能够更加灵活、稳定及可操作,国际标准化组织提出了一些网络架构模型:
OSI模型、TCP/IP模型,二者的网络模型图:
OSI(开放系统互连)模型 将网络从 底层的物理层 到 顶层浏览器的应用层 一共划分了7层,OSI各层的具体作用如下所示:
相关视频学习
学习链接
OSI是一种理论下的模型,它先规划了模型再填入协议,先制定了标准再推行实践,TCP/IP充分借鉴了OSI引入的服务、接口、协议及分层等概念,建立了TCP/IP模型并广泛使用,成为目前互联网事实上的标准。
TCP连接
根据对网络模型的了解,当使用本地主机连上网线接入互联网后,数据链路层和网络层就已经打通了,而要向目标主机发起HTTP请求,就需要通过传输层建立端到端的连接。
传输层常见的协议有TCP协议和UDP协议。
对于前端页面的资源请求,需要面向连接、丢包重发及对数据传输的各种控制,所以接下来仅详细介绍TCP协议的“三次握手”和“四次挥手”。
由于TCP是面向有连接的通信协议,所以在数据传输之前需要建立好客户端与服务器端之间的连接,即通常所说的“三次握手”,具体过程分为如下步骤。
三次握手:
(1)客户端生成一个随机数seq,假设其值为t,并将标志位SYN设为1,将这些数据打包发给服务器端后,客户端进入等待服务器端确认的状态。
(2)服务器端收到客户端发来的SYN=1的数据包后,知道这是在请求建立连接,于是服务器端将SYN与ACK均置为1,并将请求包中客户端发来的随机数t加1后赋值给ack,然后生成一个服务器端的随机数seq=k,完成这些操作后,服务器端将这些数据打包再发回给客户端,作为对客户端建立连接请求的确认应答。
(3)客户端收到服务器端的确认应答后,检查数据包中ack的字段值是否为t+1,ACK是否等于1,若都正确就将服务器端发来的随机数加1(ack=k+1),将ACK=1的数据包再发送给服务器端以确认服务器端的应答,服务器端收到应答包后通过检查ack是否等于k+1来确认连接是否建立成功。连接建立的关系图如图所示。
客户端:老哥,我要连你,你在么?(请求建立连接)
服务器:小弟,你连吧,我在线呢?(对客户端建立连接请求的确认应答)
客户端:好的,老哥,我连过来了。(确认连接建立成功)
当用户关闭标签页或请求完成后,TCP连接会进行“四次挥手” 具体过程如下:
(1) 由客户端先向服务器端发送 FIN=M 的指令,随后进入完成等待状态FIN_WAIT_1,表明客户端已经没有再向服务器端发送的数据,但若服务器端此时还有未完成的数据传递,可继续传递数据。
(2) 当服务器端收到客户端的 FIN 报文后,会先发送ack=M+1的确认,告知客户端关闭请求已收到,但可能由于服务器端还有未完成的数据传递,所以请客户端继续等待。
(3) 当服务器端确认已完成所有数据传递后,便发送带有 FIN=N 的报文给客户端,准备关闭连接。
(4) 客户端收到 FIN=N 的报文后可进行关闭操作,但为保证数据正确性,会回传给服务器端一个确认报文ack=N+1,同时服务器端也在等待客户端的最终确认,如果服务器端没有收到报文则会进行重传,只有收到报文后才会真正断开连接。而客户端在发送了确认报文一段时间后,没有收到服务器端任何信息则认为服务器端连接已关闭,也可关闭客户端信息。连接关闭的关系图如图下图所示:
只有连接建立成功后才可开始进行数据的传递,由于浏览器对同一域名下并发的TCP连接有限制,以及在1.0版本的HTTP协议中,一个资源的下载需对应一个TCP的请求,这样的并发限制又会涉及许多优化方案。
在基本了解TCP的工作原理之后,我们可以开始创建一个TCP服务器端来接受网络请求,代码如下:
TCP-server.js
var net = require("net");
var server = net.createServer(function (socket) {
socket.on("data", function (data) {
socket.write("你好");
});
socket.on("end", function () {
console.log("连接断开");
});
socket.write("欢迎光临《深入浅出Node.js》示例:\n");
});
server.listen(8124, function () {
console.log("server bound");
});
TCP-client.js:
var net = require("net");
var client = net.connect({ port: 8124 }, function () {
client.write("world!\r\n");
});
client.on("data", function (data) {
console.log(data.toString());
client.end();
});
client.on("end", function () {
console.log("client disconnected");
});
当TCP连接建立好之后,便可通过HTTP等协议进行前后端的通信。但在实际的网络访问中,并非浏览器与确定IP地址的服务器之间直接通信,往往会在中间加入反向代理服务器。