node.js的一个小例子
2018-06-24 00:28:11来源:未知 阅读 ()
安装配置的环节这里就不说了。
这是我学习nodejs以来做的第一个小例子,很简单,就是在第一个页面里输入自己的名字,在第二个页面(有图片)中显示。思路和很多地方都参考了http://www.cnblogs.com/giggle/p/6287931.html 这篇文章,感谢作者。
这篇文章中说得不对的地方希望大家指正。
客户端的步骤是进入127.0.0.1:8000/login进入login.html,填写输入框后进入mian.html。
服务器端的步骤是:
1.通过浏览器传来的url获取路由,判断进入login.html,
2.用户提交表单,在表单action方法中进入main.js,此时使用post方法,携带参数,并根据html中的{name}占位,利用node动态替换。
3.在遇到图片src时,处理图片请求。
先贴上两个html文件:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="author" content="Hx2"> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="Description" content="网页描述"/> <meta name="Keywords" content="关键字"/> <title></title> <style> form { text-align:center; } </style> </head> <body> <form action="./deliver" method="post"> 账户:<input type="text" name="name"/><br/> 密码:<input type="password" name="password"/><br/> <input type="submit" value="提交"/> </form> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="author" content="Hx2"> <meta name="format-detection" content="telephone=no"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <meta name="Description" content="网页描述"/> <meta name="Keywords" content="关键字"/> <title></title> <style> body { text-align:center; } span { color: brown; } img{ width: 100%; } </style> </head> <body> <div> hello!<span>{name}</span> </div> <img src="./showImg" /> </body> </html>
首先是主文件,创建一个服务:
1 var http = require('http'); 2 http.createServer(function(request,response) { 3 response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); 4 if(request.url!=="/favicon.ico"){ 5 6 response.end(''); 7 } 8 }).listen(8000); 9 console.log('Server running at http://127.0.0.1:8000/');
这段中引入node的自带对象http。
response.writeHead是协议头。
然后用if清除对favicon.ico的访问,否则刷新一次就会有两次访问,就避免了未知的错误。
response.end结束请求。
listen是监听某个端口。
当一个请求来到服务器的时候,他会获取到url的路径来判断接下来的操作。所以需要添加url模块,利用这个模块来获得url中的相关路径并处理。就是这句:var url = require('url');
连接到router.js文件后,此时主文件中获取路由,通过正则处理掉多余的 “ / ” 以正确匹配router.js里面的方法。同时,用try catch来处理这里可能发生的异常。
完整的main.js文件如下:
var http = require('http'); var url = require('url'); var router = require('./router.js'); http.createServer(function(request,response) { if(request.url!=="/favicon.ico"){ pathname = url.parse(request.url).pathname; pathname = pathname.replace(/\//,''); try{//如果这一部分有错误,执行下面catch router[pathname](request,response) }catch(err){ console.info('router错误' + err); response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); //协议头 response.write(err.toString()); response.end(''); } } }).listen(8000); console.log('Server running at http://127.0.0.1:8000/');
根据需求,我们需要处理的是进入login页面的login、传递名字的deliver、显示图片的showImg。所以在router.js文件中有了个基本的骨架:
module.exports = { login : function(req,res){ }, deliver : function(req,res){ }, showImg : function(req,res){ } }
在router.js里面有三个操作,他们有个共同点,就是都会读取服务器的本地文件将它写在客户端。这样,把他的操作都提取出来放在一个文件中,有利于管理和调用,这里建个optfile.js存放操作。暂定optfile.js里面有三个方法,分别是同步读取:readfileSync、异步读取:readfile、读取图片:readImg。具体操作等会说。
在router.js里的login中,如果是同步的话可以这样写,他会一步一步向下执行:
login : function(req,res){ res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); optfile.readfileSync('./view/login.html',res); res.write(data); res.end(''); },
但是node.js的优势是异步,我们需要做的是异步的。
异步读取文件的方法(在下面会说)需要一个闭包来存储此时的request和response,来保证readFile在异步执行的时候,这里的request和response不会在垃圾回收机制下被自动清除。并且在闭包中加入end()就不存在当异步还没有执行完,主程序先执行完了报错这种情况。
在后面的readFile方法里只需要调用这个闭包就可以了。
这个闭包就是下面的recall(),我们在闭包中对读取的文件进行相关的操作。
login : function(req,res){ response.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); function recall(data){ res.write(data); res.end(''); }; optfile.readfile('./view/login.html',recall) }
在操作比较多的项目中,每一个相同操作(这里是显示到客户端)都要写一个recall函数非常麻烦,所以封装成getRecall方法:
function getRecall(req,res){ res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); function recall(data){ res.write(data); res.end(''); } return recall; }
这样,login就变得很简洁:
login : function(req,res){ recall = getRecall(req,res);//这个recall并不是getRecall,而是getRecall返回的闭包recall optfile.readfile('./view/login.html',recall) },
在router.js里的deliver中,需要使用post或get方法传参,这里使用post方法:
var post = ''; req.on('data',function(chunk){ post += chunk; }) req.on('end',function(){ post = querystring.parse(post); console.log('收到参数:' + post['name值'] + '\n'); }
这时的思路是把收到的参数显示在main.html中,在main.js中接收参数(如果是多个就使用数组),而deliver方法就是带着参数跳转到main.js中。所以想到接下来的步骤应该是:
recall = getRecall(req,res);
optfile.readfile('./view/main.html',recall);
但是上面的post方法相对于上面的两句是异步的,异步传参,所以为了确保这两句在post方法后执行,可以把他放在end事件中。
在recall函数里,他要做的就不仅仅是显示在页面那么简单,而是要寻找到带{}标记的元素,把他替换为传来的参数,重写recall:
function recall(data){ dataStr = data.toString();//字符串 re = new RegExp('{name}','g');//new RegExp和/.../的区别是他可以在里面直接用字符串拼接的形式表示 dataStr = dataStr.replace(re,post['name值']); res.write(dataStr); res.end(); } optfile.readfile('./view/main.html',recall);
如果需要传输多个参数,使用数组
arr = ['email','pwd']; function recall(data){ dataStr = data.toString(); for(var i = 0; i < arr.length; i++){ re = new RegExp('{' + arr[i] + '}','g'); dataStr = dataStr.replace(re,post[arr[i]]); } res.write(dataStr); res.end(); }
第三个showImg,协议头改成请求图片的协议头,然后读取图片即可:
showImg : function(req,res){ res.writeHead(200,{'Content-Type':'image/jpeg'}); optfile.readImg('./src/xin2.jpg',res); }
完整的router.js:
var optfile = require('./models/optfile.js');
var url = require('url');
var querystring = require('querystring');//post需导入
function getRecall(req,res){
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
function recall(data){
res.write(data);
res.end('');
}
return recall;
}
module.exports = {
login : function(req,res){
recall = getRecall(req,res);//这个recall并不是getRecall,而是getRecall返回的闭包recall
optfile.readfile('./view/login.html',recall)
},
deliver : function(req,res){
var post = '';
req.on('data',function(chunk){
post += chunk;
})
req.on('end',function(){
post = querystring.parse(post);
console.log('收到参数:' + post['name'] + '\n');
console.log('收到参数:' + post['password'] + '\n');
function recall(data){
dataStr = data.toString();
re = new RegExp('{name}','g');
dataStr = dataStr.replace(re,post['name']);
res.write(dataStr);
res.end();
}
optfile.readfile('./view/main.html',recall);
})
},
showImg : function(req,res){
res.writeHead(200,{'Content-Type':'image/jpeg'});
optfile.readImg('./src/xin2.jpg',res);
}
}
来说optfile.js了!optfile.js暂时有三个操作,同、异步读文件和读取图片。
var fs = require('fs'); module.exports = { readfileSync : function(path){ var data = fs.readFileSync(path,'utf-8'); }, readfile : function(path,res){ fs.readFile(path,function(err,data){ if(err){ console.log('读文件异常!'); }else{ console.log('读好了'); } }) }, readImg : function(path,res){ ... } }
大概这么写,但是上面有说,如果想在readFile中添加一个操作,比如说需求中将data显示在客户端,此时可能的思路是把console.log('读好了');替换为res.write(data) 之类。但是不对。因为readFile方法是异步的,在异步里,主线程执行过程中会有很多分线程来执行各种不同的操作,但分线程并不影响主线程的执行。在读取文件的这个分线程中,如果直接执行res.write(data)会报错,因为主线程此时可能已经执行完了。
所以这里要调用到之前写的闭包。虽然recall()在这个线程中执行,但原来的response并没有被清除掉,还在等待着recall();当recall返回一个data时,原来的response接收到了,进行操作。这个闭包储存了原来的req和res用来操作,并解决了分线程end的问题。
readfile : function(path,recall){ fs.readFile(path,function(err,data){ if(err){ console.log('读取文件分线程错误:'+err); recall('文件不存在'); }else{ console.log('异步读取文件data为:' + data.toString()); recall(data); } }) console.info('异步读取文件方法执行了'); },
如果readFile这里异步线程出错,主线程可以执行,异步可以读取出来,但如果这里有错误并且没有回调recall('文件不存在');的话,记载图标会一直转,所以这里处理异常要使用recall('文件不存在'),其中包括错误提示和结束线程。
readImg和文件读取差不多,就是图片需要用二进制流'binary'的方式读取。
完整的optfile.js:
var fs = require('fs'); module.exports = { readfileSync : function(path){ var data = fs.readFileSync(path,'utf-8'); console.info('同步读取文件执行完毕,data为:' + data); }, readfile : function(path,recall){ fs.readFile(path,function(err,data){ if(err){ console.log('读取文件分线程错误:'+err); recall('文件不存在'); }else{ recall(data); } }) console.info('异步读取文件方法执行了'); }, readImg : function(path,res){ fs.readFile(path,'binary',function(err,imgdata){ if(err){ console.log('读图片分线程错误:'+ err); return; }else{ res.write(imgdata,'binary'); res.end(''); } }) } }
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- jQuery异步提交表单的两种方式 2020-03-12
- 默认让页面的第一个控件选中的javascript代码 2020-02-20
- Node.js中环境变量process.env的一些事详解 2020-01-17
- 详解node.js进行web开发的操作方法 2019-12-14
- 将数组扁平化并去除其中重复数据,最终得到一个升序且不重复 2019-08-14
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash