一、浏览器发送请求
1、用户输入网址
http://127.0.0.1/
2、浏览器根据请求转变HTTP的请求包
GET / HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
二、服务器接收到请求
1、http模块里实例化的server对象,server对象监听每一次浏览器发送过来的请求,每次的请求都会触发request事件
this.server.on("request",(req,res)=>{})
2、将HTTP的请求包转换成req的请求对象,并且传入到请求事件触发的函数中。
3、会创建生成一个res响应对象,这个对象可以帮助我们快速的实现HTTP的响应。
三、解析请求路径,调用不同的页面渲染函数
1、正则匹配方式进行对路径的匹配。
2、以匹配的正则字符串作为KEY,找到需要调用执行的渲染函数
//循环匹配正则路径
for(let key in this.reqEvent){
let regStr = key
let reg = new RegExp(regStr,'igs');
if(reg.test(req.url)){
this.reqEvent[key](req,res);
resState = true
break;
}
}
3、调用页面的执行函数,执行模板渲染
app.on('/movies/[01]',(req,res)=>{}) //这里的箭头函数即为真正匹配到的页面执行的函数
4、调用模板的渲染函数
res.render(movies[index],'./template/index1.html')
5、执行渲染函数
function render(options,path) {
fs.readFile(path,{encoding:"utf-8",flag:"r"},(err,data)=>{
if(err){
console.log(err)
}else{
try{
data = replaceArr(data,options)
data = replaceVar(data,options)
}catch(error){
console.log(error)
}
this.end(data)
}
})
}
6、数组变量的替换
function replaceArr(data,options){
//匹配循环的变量,并且替换循环的内容
let reg = /\{\%for \{(.*?)\} \%\}(.*?)\{\%endfor\%\}/igs
while(result = reg.exec(data)){
let strKey = result[1].trim();//提取变量时,去掉左右两边的空格
//通过key值获取数组的内容
let strValueArr = options[strKey]
let listStr = ""
strValueArr.forEach((item,i) => {
//替换每一项内容里的变量
listStr = listStr + replaceVar(result[2],{"item":item})
});
data = data.replace(result[0],listStr)
}
return data
}
7、单个变量的替换
function replaceVar(data,options) {
//匹配普通的变量,并且替换内容
let reg = /\{\{(.*?)\}\}/igs
let result;
while (result = reg.exec(data)){
//去除两边的空白
let strKey = result[1].trim();
//options.item
let strValue = eval('options.'+strKey);//执行字符串作为JS表达式,并将计算出来的结果返回
data = data.replace(result[0],strValue)
}
return data
}
四、如果是请求静态文件,那么就按照静态文件的形式输出
1、首先判断是否响应过,如果没有响应过,可以判断是否为静态文件,如果是静态文件就正常的输出
2、否则就输出404
if(!resState){
try{
if(pathObj.dir==this.staticDir){
res.setHeader("content-type",this.getContentType(pathObj.ext))
let rs = fs.createReadStream('./static/'+pathObj.base)
rs.pipe(res)
}else{
res.setHeader("content-type","text/html;charset=utf-8")
res.end("<h1>404!页面找不到</h1>")
}
}catch(error){
console.log(error)
}
}
五、RES响应对象将res设置的内容最终转化成http的响应包
HTTP/1.1 200 OK
content-type: text/html;charset=utf-8
Date: Thu, 23 Jul 2020 12:17:19 GMT
Connection: keep-alive
Content-Length: 53
正文内容
六、浏览器解析响应包,并将html渲染在页面上