Node.js初体验
前言
刚刚看完了《Node.js入门》,参考node官网和一些相关文章,终于感觉和node亲近了一步,迫不及待的想写篇文章分享一下,希望本文的读者读完后像读了一本好书一样,获益良多。
ps:《Node.js入门》一书仅有38页,是一本很好的入门书籍,如果你也是刚上手node,和我一样手中有一本《深入浅出node.js》相似的高级书籍,但感觉读起来晦涩难懂,不如试试《Node.js入门》吧,会感觉豁然开朗,
借用《Node.js入门》中的编程应用,稍作修改,加上自己的一些思考,讲一下“异步,事件驱动与回调,非阻塞”这些使node.js轻便和高效的特点。特点穿插在应用中讲解。如有错误,欢迎指教!
应用目标:
• 用户可以通过浏览器使用我们的应用。
• 当用户请求http://domain/start时,可以看到一个欢迎页面,页面上有一个 文件上传的表单。
• 用户可以选择一个图片并提交表单,随后文件将被上传到 http://domain/upload,该页面完成上传后会把图片显示在页面上。
实现思路
先来思考一下怎样实现这样一个应用呢?
--啊,要实现应用了,我我...还不知道代码写在哪里,
首先我们要用node跑起js来。
--看用户的请求,这个应用是是跑在服务器的,node要链接服务器吗?
node中可以加载‘http’模块,可以让我们轻松的搭建服务器,真的一点也不难哦。
--还可以学习模块的加载,简直是福利多多,咦,请求页面和显示页面不是一个路径,这个要怎么实现呀?
我们可以创建一个路由模块,对不同的请求有不同的处理,再用总文件将请求路由到相应的处理程序。
--哇哦,有了这个路由机制,我们就可以将start 的路由处理程序设置为上传图片,将upload的处理程序设置为显示图片了
没错,大体的思路就是这样,让我们开始上手吧!
应用实现:
跑起node
首先要让node跑起js来
我们知道,node.js是一个基于chrome V8的一个javaScript运行环境,所以我们这里说的是让node.js跑起js来,而不是让node.js跑起来。
我们先创建一个 helloworld.js 程序,内容为:
console.log("Hello World");
然后在命令行终端中用 node 运行本文件:
node helloworld.js
终端中就会运行出js的结果:Hello World
创建服务器
接下来我们来创建服务器,创建一个server.js文件:
var http = require("http");//引入node内置的‘http’模块http.createServer(function(request, response) {//创建一个服务器,并在创建方法中规定服务器触发请求的回调函数 response.writeHead(200, {"Content-Type": "text/plain"});//规定响应头部信息(状态码和文本格式) response.write("Hello World");//设定了响应的内容 response.end();//响应结束}).listen(8888);//设定服务器监听8888端口。console.log("Server has started.");
用node跑一下:
node server.js
终端的输出结果为:
Server has started.Request received.
浏览器端访问:http://localhost:8888/ 显示结果为:
Hello World
代码解读:
1.模块调用
我们把一定实现一定功能的代码放在一个文件里,这个文件也就是一个模块,要实现模块间的调用,就需要模块导出和模块引入,
这里‘http’模块是node内置的,他自身有导出功能,(一会我们还要自己实现模块的导出功能),我们引入了‘http’模块,便能应用它的功能了。
2.事件回调
http的createServer方法,需要传入一个参数,这个参数是一个函数(js中函数是可以作为参数传递的),当请求事件发生时便会触发这个函数,这便是回调函数,回调函数可以是匿名的(就像我们这里一样),也可以是命名的。
事件回调就是:知道有一些事情随时可能发生,回调函数时刻准备着对将要发生的事件作出响应
3.http相关解读:
- createServer函数参数解读:
createServer的函数参数中有两个参数,第一个表示请求,可以规定请求相关的内容(这里用'request'表示,也可以用'req'...叫什么都可以),第二个表示响应,可以规定响应相关的内容(这里用'response'表示).
- createServer返回值解读:
createServer返回一个http.server的实例,通过这个server实例调用listen方法,规定了监听的端口号。
加入路由
我们设置路由及相应处理程序,并把请求和他们关联起来
这里有4个程序,需要都看完才能理解,建议大家亲自跑一下。
四个程序关联图:
'+
''+
''+
''+
''+ ''+ ''+
''+
'';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, postData) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent: " + querystring.parse(postData).text);//因为我们只关注文本的内容,所以这里专门解析出文本内容。
response.end();
}
exports.start = start;
exports.upload = upload;
不用修改index.js感觉离成功很近了,现在的问题就是我们把文本改成图片,文本可以用一个参数存储,图片呢?图片一般是通过路径来操作的,怎么通过路径存储图片呢?怎么知道图片上传后存在哪里呢?node中有什么关于请求资源路径的模块吗?真的有诶,那就是node-formidable模块,先把它下载下来:
npm install formidable
看下它如何工作:
var formidable = require('formidable'),
http = require('http'),
sys = require('util');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
// parse a file upload
var form = new formidable.IncomingForm();//获取到表单
form.parse(req, function(err, fields, files) {//对表单内容进行解析
res.writeHead(200, {'content-type': 'text/plain'});
res.write('received upload:\n\n');
res.end(sys.inspect({fields: fields, files: files}));
});
return;
}
// show a file upload form
res.writeHead(200, {'content-type': 'text/html'});
res.end(''
);
}).listen(8888);
案例并不难,很好理解,就是页面提交了post请求,然后post页面接收到表单,随便选了一个文件,它解析的表单内容如下:received upload:
{ fields: { title: '' },
files:
{ upload:
File {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
size: 13435,
path: '/var/folders/2w/dr7185jx1y78vc215d29dp6c0000gn/T/upload_d50704d47069efb62043db1fdc868ae4',
name: 'tide.png',
type: 'image/png',
hash: null,
lastModifiedDate: 2016-06-23T11:44:45.463Z,
_writeStream: [Object] } } }
重点是path字段,它能解析到资源的路径我们试着想一下,最终应用该如何实现呢?首先start页面可以进行文件的上传,我们选择了一张图片,表单被提交到upload请求,upload可以拿到post请求的资源的路径,然后我们把路径指向的文件给打印出来开始吧,可是有个问题啊,upload显示内容的操作是在requestHandlers.js处理程序中的,解析文件路径的操作当然也要在处理程序中,可是解析需要拿到request参数,而request参数是在server.js中设置的,这里我们就要像迁移response那样,也去迁移一下request,当然不需要postData了,去掉它。修改server.js,去掉postData,传递request参数。
var http = require("http");
var url=require('url');
function start(route,handle) {
function onRequest(request, response) {
var pathname=url.parse(request.url).pathname;
console.log('Request for '+pathname+' received.');
route(handle,pathname,response,request);
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start=start;
修改router.js,传递request参数:
function route(handle,pathname,response,request) {
console.log("About to route a request for " + pathname);
if(typeof handle[pathname]==='function'){
handlepathname;
}else{
console.log("No request handler found for "+pathname);
response.writeHead(404,{"Content-Type":"text/plain"});
response.write("404 Not found");
response.end();
}
}
exports.route = route;
修改requestHandlers.js,实现应用逻辑:
var querystring=require("querystring"),
fs=require("fs");//引入文件模块
formidable=require("formidable");
function start(response) {
console.log("Request handler 'start' was called.");
var body = ''+
''+
''+
''+
''+
''+
''+
'';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response,request) {
var form=new formidable.IncomingForm();
console.log("about to parse");
form.parse(request,function (error,fields,files) {
console.log("parsing done");
fs.readFile(files.upload.path,"binary",function (error,file) {//读取保存图片的文件
if(error){//如果发生读取错误,返回错误信息
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(error+'\n');
response.end();
}else{//如果正确读取到图片就显示它
response.writeHead(200, {"Content-Type": "image/png"});
response.write(file,"binary");
response.end();
}
});
})
}
exports.start = start;
exports.upload = upload;
index.js不用修改展示下效果吧:访问start页面,我选择了一只泰迪熊的照片上传:点击Upload file按钮,当当当当:#node.js#
版权声明
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!