终极目标:掌握和使用node
本博客目的:记录node学习的进度和心得
内容:Nodejs中的NodeJs WEB服务器、静态文件托管、 路由、EJS模板引擎、GET、POST。
Nodejs 静态文件托管
上一个blog介绍了如何使用nodejs创建一个WEB服务器,用于静态文件托管。
但我们会发现,大量的代码写在一块,比较混乱。其实我们可以把一些代码封装为一个模块(router.js),然后使得服务器代码简化:

即大量的读取文件等操作(路由操作),封装为一个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; }
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,处理不同的业务逻辑。

通常我们要获取URL,从而执行不同的操作,这就是nodejs的路由。
例如url的pathname存在login或register,要进行一些操作时:

当
当
类似地,可以通过根据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的语法)


现在就是想输入带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
| var http=require('http');
var url=require('url');
var ejs=require('ejs');
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);
|
页面结果:

类似地,我们还可以定义很多views,例如register等。
这样就实现了后台渲染。(之前vue学习的单页应用是前端渲染)
Get、Post
超文本传输协议(HTTP)的设计目的是保证客户端机器与服务器之间的通信。 在客户端和服务器之间进行请求-响应时,两种最常被用到的方法是:GET 和 POST。
GET - 从指定的资源请求数据。(一般用于获取数据)
POST - 向指定的资源提交要被处理的数据。(一般用于提交数据)
现在,我们有个需求,当打开/login的url时,显示登录页面,例如一个登录的表单(通常表单的提交信息是通过post,提交给服务器):

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


所以,通常我们是在打开登录页面,输入用户名和密码,然后提交。
首先,我们要判断客户端请求的方法是get还是post。(通过req对象method属性)
获取请求的方法,判断是post还是get:

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

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

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

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

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

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


可以获取客户端提交的信息。
如果表单以post方法:

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

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


注意:此时,post方式不会把数据像get方式哪样拼接在url后面,而是放在请求头里。
打开浏览器控制台,的确是post方式,参数也正确:


服务器也正确获取数据:

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


再之后,通常如果认证成功,则会让客户端进行页面跳转。
小结:这样就可以用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
|
var http=require('http');
var url=require('url');
var ejs=require('ejs');
var fs=require('fs');
http.createServer(function(req,res){
res.writeHead(200,{"Content-Type":"text/html;charset='utf-8'"});
var method=req.method.toLowerCase();
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'){
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){
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);
|