终极目标:掌握和使用node

本博客目的:记录node学习的进度和心得

内容:Nodejs中的NodeJs WEB服务器、静态文件托管、 路由、EJS模板引擎、GET、POST。

Nodejs 静态文件托管

​ 上一个blog介绍了如何使用nodejs创建一个WEB服务器,用于静态文件托管。

​ 但我们会发现,大量的代码写在一块,比较混乱。其实我们可以把一些代码封装为一个模块(router.js),然后使得服务器代码简化:

image-20200515154119924

​ 即大量的读取文件等操作(路由操作),封装为一个router.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
var fs=require('fs');

var path=require('path');

var url=require('url');


function getMime(extname,callback){

fs.readFile('./mime.json',function(err,data){

if(err){

return false;
}
//console.log(data.toString());

var Mimes=JSON.parse(data.toString());

var result= Mimes[extname] || 'text/html';

callback(result)

})


}

exports.statics=function(req,res,staticpath){


var pathname=url.parse(req.url).pathname;


if(pathname=='/'){
pathname='/index.html';
}

var extname=path.extname(pathname);

if(pathname!='/favicon.ico'){


fs.readFile(staticpath+'/'+pathname,function(err,data){

if(err){

console.log('404');

fs.readFile(staticpath+'/404.html',function(error,data404){
if(error){
console.log(error);
}
res.writeHead(404,{"Content-Type":"text/html;charset='utf-8'"});
res.write(data404);
res.end();
})

}else{

getMime(extname,function(mime){
res.writeHead(200,{"Content-Type":""+mime+";charset='utf-8'"});
res.write(data);
res.end();
});

}
})

}

}

​ 这样同样能够实现之前写的静态服务器的功能。

路由

​ 路由(Routing)是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应客户端对某个网站节点的访问。

​ 即路由指的就是针对不同请求的URL,处理不同的业务逻辑。

image-20200515153020139

​ 通常我们要获取URL,从而执行不同的操作,这就是nodejs的路由。

​ 例如url的pathname存在login或register,要进行一些操作时:

image-20200515155114068

image-20200515155148412

image-20200515155215506

类似地,可以通过根据URL,来自定义自己想要的操作。

​ 但是,我们发现这样的写法,还是有点混乱。这时候我们可以使用模板引擎。

EJS模块引擎(属于后台渲染)

​ 我们学的EJS是后台模板,可以把我们数据库和文件读取的数据显示到Html页面上面。

它是一个第三方模块,需要通过npm安装
https://www.npmjs.com/package/ejs

npm install ejs -–save

(CMD当前目录,安装。会自动在项目中生成package.json。但通常还是在写项目初期,使用npm init来生成)

​ 现在,我们还是想服务器能够根据不同的URL,执行一些不同的操作。例如,我们输入login的URL时,要加载login的页面,但是按照之前的方法,只能加载之前写好在静态文件夹中的静态文件,我们希望的是能够把(后台)数据库的数据渲染到模板上。

​ 这时可以使用EJS模块引擎。EJS提供了renderFile方法,用于渲染模板。

​ 还有一些常用标签:

​ <% %>流程控制标签

​ <%= %>输出标签(原文输出HTML标签)

​ <%- %>输出标签(HTML会被浏览器解析)

​ 因此,首先,通常我们会在项目中,创建视图文件夹(放置模板)views,然后在里面创建.ejs为后缀名的模板。(.ejs是为了能够使用ejs的语法)

image-20200515161252637

image-20200515162226112

​ 现在就是想输入带login的URL就转入到这个login.ejs页面,并且传入一些数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//引入http模块
var http=require('http');

var url=require('url');

var ejs=require('ejs');

//路由:指的就是针对不同请求的 URL,处理不同的业务逻辑。
http.createServer(function(req,res){

res.writeHead(200,{"Content-Type":"text/html;charset='utf-8'"});


var pathname=url.parse(req.url).pathname;

if(pathname=='/login'){

var data='i am backend data ';

var list=[


'1111',
'2222',
'3333',
];

//把数据库的数据渲染到模板上面
ejs.renderFile('views/login.ejs',{
msg:data,
list:list
},function(err,data){

res.end(data);

})



}

}).listen(8001);

页面结果:

image-20200515162716412

​ 类似地,我们还可以定义很多views,例如register等。

​ 这样就实现了后台渲染。(之前vue学习的单页应用是前端渲染)

Get、Post

​ 超文本传输协议(HTTP)的设计目的是保证客户端机器与服务器之间的通信。 在客户端和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST。

GET - 从指定的资源请求数据。(一般用于获取数据)

POST - 向指定的资源提交要被处理的数据。(一般用于提交数据)

​ 现在,我们有个需求,当打开/login的url时,显示登录页面,例如一个登录的表单(通常表单的提交信息是通过post,提交给服务器):

image-20200515193645489

当url带login时,渲染到form.ejs页面

image-20200515193708858

image-20200515193855994

​ 所以,通常我们是在打开登录页面,输入用户名和密码,然后提交。

​ 首先,我们要判断客户端请求的方法是get还是post。(通过req对象method属性)

​ 获取请求的方法,判断是post还是get:

image-20200515194203770

​ 如果客户端请求方法是get,则这个信息会query字段拼接在URL后面。服务器要获取这个信息,需要对这个URL进行解析。

​ 如果表单为get方法:

image-20200515195020064

​ 例如输入wu12和123,然后点击登录:

image-20200515194935674

注意:当提交表单时,我们修改了路径:

image-20200515195721831

所以是在这个路径下拼接了query信息。

image-20200515194947895

打开控制台,的确是以get方法,请求数据,query的参数也正确:

image-20200515200449838

​ 服务器可直接解析这个url:

image-20200515195312424

image-20200515195321959

​ 可以获取客户端提交的信息。

​ 如果表单以post方法:

image-20200515195113481

​ 例如分别输入wu123和123,然后点击登录:

image-20200515194352025

我们可以设置一个弹窗alert,说明登录成功:

image-20200515201333965

image-20200515194433532

注意:此时,post方式不会把数据像get方式哪样拼接在url后面,而是放在请求头里。

打开浏览器控制台,的确是post方式,参数也正确:

image-20200515200658929

image-20200515200725397

服务器也正确获取数据:

image-20200515194521441

同时,我们还可以设置服务器获取传值,然后写入login.txt保存数据(后面学习数据库还会使用数据库,继续加深理解):

image-20200515195954343

image-20200515200008095

再之后,通常如果认证成功,则会让客户端进行页面跳转。

小结:这样就可以用nodejs实现后端路由,即根据不同URL和请求方法,执行不同操作,例如网页跳转,数据展示,数据获取等。

但是,我们把get和post操作都写到了服务器代码中,显得很大很臃肿,后续应该进行封装(封装仿照express框架的路由)。

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

//引入http模块
var http=require('http');

var url=require('url');

var ejs=require('ejs');

var fs=require('fs');

//路由:指的就是针对不同请求的 URL,处理不同的业务逻辑。
http.createServer(function(req,res){

res.writeHead(200,{"Content-Type":"text/html;charset='utf-8'"});


//获取get 还是post请求


var method=req.method.toLowerCase();
//console.log(method);

var pathname=url.parse(req.url,true).pathname;


if(pathname=='/login'){ /*显示登录页面*/


ejs.renderFile('views/form.ejs',{

},function(err,data){


res.end(data);

})


}else if(pathname=='/dologin' &&method=='get'){ /*执行登录的操作*/


//get获取数据
console.log(url.parse(req.url,true).query);

res.end('dologin');



}else if(pathname=='/dologin' &&method=='post'){ /*执行登录的操作*/


var postStr='';
req.on('data',function(chunk){

postStr+=chunk;
})
req.on('end',function(err,chunk){

//res.end(postStr);
console.log(postStr);

fs.appendFile('login.txt',postStr+'\n',function(err){

if(err){
console.log(err);
return;
}
console.log('写入数据成功');
})

res.end("<script>alert('登录成功');history.back();</script>")

})


}else{

ejs.renderFile('views/index.ejs',{

},function(err,data){

res.end(data);

})
}

}).listen(8001);