nodejs上传图片并显示的例子
目标
1. 在浏览器地址栏输入“http://demos/start”,进入欢迎页面,页面有一个文件上传表单;
2. 选择一张图片并提交表单,文件被上传到"http://demos/uploads"上传完成把该图片显示在页面上。
功能模块分解
1. 需要提供欢迎页,所以需要一个http服务器;
2. 对于不同请求,根据url,服务器能给与不同响应,需要路由,把请求对应到相应的请求处理程序(request handler)
3. 需要请求处理程序;
4. 路由处理post数据,并把数据封装成更加友好的格式传递给处理程序,需要数据处理功能;
5. 需要视图逻辑供请求处理程序使用,以便将结果返回给浏览器;
6. 需要上传处理功能处理上传细节。
如果是php实现,我们需要apache http服务器并配置mod_php5模块,那么整个“接收请求并回复“并不需要php来做。而使用nodejs,不仅仅是实现应用,同时还实现了http服务器。
一个基础的http服务器
nodejs支持模块化,有利于编写干净的代码。除了内置的模块,我们可以将自己的不同功能的代码放进不同模块中,说白了就是写在不同文件中。
创建js文件取名server.js,写入代码如下:
1 var http = require('http');
2
3 http.createServer(function(req,res){
4 res.writeHead(200,{'Content-Type':'text/html'});
5 res.write('<h1>Node.js</h1>');
6 res.end("");
7 }).listen(3000,'127.0.0.1');
node server.js
浏览器输入"http://localhost:3000",显示”Node.js“。
服务器简单分析
第一行,require请求nodejs内置的http模块,赋给http变量;接着调用http模块的createServer方法,返回一个对象,这个对象有一个叫做listen的方法,这个方法的参数指定http服务器监听的端口号。createServer方法的匿名函数是该方法仅仅需要的一个参数,js中函数和变量一样可以传递。
使用这种方式是因为nodejs是事件驱动的。
当我们使用php时,任何时候每当有请求进入,apache就为这一新请求新建一个进程,并从头到尾的执行php脚本。htpp.createServer不仅仅是建一个侦听某端口的服务器,我们还想要他在收到http请求时做点什么。而nodejs是异步的:请求任何时候都可能到达,但是他却跑在一个单进程中。
当一个请求到达3000端口时怎么控制流程呢?这时候nodejs/javascript的事件驱动机制派上用场了。
我们向创建服务器的方法传递了一个函数,任何时候服务器收到请求,这个函数就会被调用,被用作处理请求的的地方。
服务器如何处理请求
当服务器加收请求回调的匿名函数被触发的时候,有两参数传入:request和response。利用这两个对象的方法处理请求的细节,并返回应答。
使用response.writeHead()发送一个http状态200和http头的内容类型等,使用response.write()在响应主体中发送文本,而使用response.end()完成应答。
封装为模块:
1 var http = require('http');
2
3 function serverStart(){
4 http.createServer(function(req,res){
5 console.log('http request recieve');
6
7 res.writeHead(200,{'Content-Type':'text/html'});
8 res.write('<h1>Node.js</h1>');
9 res.end("");
10 }).listen(3000,'127.0.0.1');
11
12 console.log('http server start on port 3000');
13 }
14
15 exports.serverStart = serverStart;
第一行http是内置的模块,这里封装了我们自己的模块,通过关键字exports露出接口方法,模块名为该文件名server,之后”server模块“可以被其他模块引用。
创建index.js文件,写入代码并引用server模块:
1 var server = require("./server");
2
3 server.serverStart();
对请求进行路由选择
为路由提供请求的url和其他GET和POST参数,路由根据这些数据来分发请求到具体的处理程序。因此,我们需要查看并解析http请求,提取出url和get/post参数,暂且将这一解析功能归于http服务器一部分。请求数据都包含在request对象中,引入内置模块url和querystring来解析它。
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(){
5 http.createServer(function(req,res){
6 var pathname = url.parse(req.url).pathname;
7 console.log('http request for '+pathname+' recieved');
8
9 res.writeHead(200,{'Content-Type':'text/html'});
10 res.write('<h1>Node.js</h1>');
11 res.end("");
12 }).listen(3000,'127.0.0.1');
13
14 console.log('http server start on port 3000');
15 }
16
17 exports.serverStart = serverStart;
通过第6行的解析,不同的请求路径在第7行输出不同的pathname。
建立一个名为router.js的文件,编写路由代码如下:
1 function route(pathname){
2 console.log('about to route a request for'+pathname);
3 }
4
5 exports.route = route;
服务器应该知道路由的存在,并加以组合有效地利用。这里可以采用硬编码方式或依赖注入的方式实现组合,后者更好。
改造server.js如下:
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(route){
5 http.createServer(function(req,res){
6 var pathname = url.parse(req.url).pathname;
7 console.log('http request for '+pathname+' recieved');
8
9 route(pathname);
10
11 res.writeHead(200,{'Content-Type':'text/html'});
12 res.write('<h1>Node.js</h1>');
13 res.end("");
14 }).listen(3000,'127.0.0.1');
15
16 console.log('http server start on port 3000');
17 }
18
19 exports.serverStart = serverStart;
改造index.js如下:
1 var server = require("./server");
2 var router = require("./router");
3
4 server.serverStart(router.route);
编译运行,可看到路由模块被server模块引入。
行为驱动执行
在index中,我们将router对象传递进去,服务器随后调用这个对象的route函数。但其实服务器自身并不需要这个对象,它只是需要执行某个动作,而这个动作由该对象来完成。具体的细节服务器并不关心,因为这是执行这个动作的那个对象的事。这就是函数式编程。但归根结底,到了最后一层总有一个对象是真正关心细节并完成细节,输出结果的。像现实世界的上级把任务给下级,下级给再下级,最终总要有人完成这个任务才好!
路由到处理程序
路由用来转发请求,将请求分发给实际的处理程序,让他们解决请求并回复,因此新建请求处理模块requestHandlers.js,代码如下:
1 function start(){
2 console.log("request handler 'start' was called");
3 }
4
5 function upload(){
6 console.log("request handler 'upload' was called");
7 }
8
9 exports.start = start;
10 exports.upload = upload;
有了这个模块,路由就有路可寻了。
现在需要将处理程序通过一个对象来传递并将对象注入到route()函数中,而javascript的对象是”key:value“组合,满足我们的需要。将存放处理程序的对象引入index,如下:
1 var server = require("./server");
2 var router = require("./router");
3 var requestHandlers = require("./requestHandlers");
4
5 var handler = {};
6 handler['/'] = requestHandlers.start;
7 handler['/start'] = requestHandlers.start;
8 handler['/upload'] = requestHandlers.upload;
9
10 server.serverStart(router.route,handler);
路径为”/“或"/start"的请求由start处理,"/upload"由upload处理。
将该对象作为参数传给服务器,server.js模块代码改为:
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(route,handle){
5 http.createServer(function(req,res){
6 var pathname = url.parse(req.url).pathname;
7 console.log('http request for ''+pathname+'' recieved');
8
9 route(handle,pathname);
10
11 res.writeHead(200,{'Content-Type':'text/html'});
12 res.write('<h1>Node.js</h1>');
13 res.end("");
14 }).listen(3000,'127.0.0.1');
15
16 console.log('http server start on port 3000');
17 }
18
19 exports.serverStart = serverStart;
handle对象传递给了route,此时还得修改router模块,如下:
1 function route(handle,pathname){
2 console.log('about to route a request for'+pathname);
3
4 if(typeof handle[pathname] === 'function'){
5 handle[pathname]();
6 }
7 else{
8 console.log('no request handler found for'+pathname);
9 }
10 }
11
12 exports.route = route;
首先检查对应的处理程序是否存在,存在则直接调用相应的函数,否则提示没有找到对应的函数。这时,服务器,路由,处理程序就联系在一起了。
让请求处理程序作出响应
web程序一般是基于http的请求-应答模式,这样服务器和浏览器可以实现通话。
一种不好的实现方式
这种方式让服务器的函数直接返回展示给用户的信息。这就需要同时修改服务器、路由、请求处理函数的部分代码:
requestHandlers.js
1 function start(){
2 console.log("request handler 'start' was called");
3 return "hello start!";
4 }
5
6 function upload(){
7 console.log("request handler 'upload' was called");
8 return "hello upload!";
9 }
10
11 exports.start = start;
12 exports.upload = upload;
requestHandlers.js
1 function route(handle,pathname){
2 console.log('about to route a request for'+pathname);
3
4 if(typeof handle[pathname] === 'function'){
5 return handle[pathname]();
6 }
7 else{
8 console.log('no request handler found for'+pathname);
9 return "404 not found!"
10 }
11 }
12
13 exports.route = route;
server.js
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(route,handle){
5 http.createServer(function(req,res){
6 var pathname = url.parse(req.url).pathname;
7 console.log('http request for '+pathname+' recieved');
8
9
10 res.writeHead(200,{'Content-Type':'text/html'});
11 var content = route(handle,pathname);
12 res.write(content);
13 res.end("");
14 }).listen(3000,'127.0.0.1');
15
16 console.log('http server start on port 3000');
17 }
18
19 exports.serverStart = serverStart;
这样的模式运行的也很好,但当有请求处理程序需要执行非阻塞操作,就“挂”了。
阻塞与非阻塞
修改requestHandlers.js
1 function start(){
2 console.log("request handler 'start' was called");
3
4 function sleep(milliSeconds){
5 var startTime = new Date().getTime();
6 while(new Date().getTime() < startTime + milliSeconds)
7 ;
8 }
9
10 sleep(10000);
11 return "hello start!";
12 }
13
14 function upload(){
15 console.log("request handler 'upload' was called");
16 return "hello upload!";
17 }
18
19 exports.start = start;
20 exports.upload = upload;
上述的sleep函数会让方法停顿10秒,然后才会返回结果。实际场景中,需要计算或是查找数据库等阻塞操作非常多。
现在通过start和upload即可模拟阻塞,打开两个空白页面分别输入“localhost:3000/start”和"localhost:3000/upload",先进行start请求在快速切换到量以页面进行upload请求,发现start页面请求恢复用了10秒,而upload也用了10秒。原因是,start中的sleep阻塞了所有其他处理。
而nodejs的特性之一是——单线程,可以在不增加线程情况下,对任务进行并行处理。这里的机制是它使用轮询(event loop)来实现并行操作,所有尽量避免阻塞操作而是用非阻塞操作。要使用非阻塞,需要使用回调,将函数作为参数传递给其他需要费时间处理的函数。
对于nodejs可以形象比喻成“嘿,probablyExpensiveFunction()(需要费时间处理的函数),继续做你的事情,我(nodejs线程)先不等你了,继续去处理后面的代码,请你提供一个回调callBackFunction(),等你处理完了我会去调用该回调函数的。”
一种错误的非阻塞方式
requestHandlers.js
1 var exec = require("child_process").exec;
2
3 function start(){
4 console.log("request handler 'start' was called");
5 var content = "empty";
6
7 exec("ls-lah",function(error,stdout,stderr){
8 content = stdout;
9 });
10 return content;
11 }
12
13 function upload(){
14 console.log("request handler 'upload' was called");
15 return "hello upload!";
16 }
17
18 exports.start = start;
19 exports.upload = upload;
引入另一个模块“child_process”,实现非阻塞操作exec()。
exec()的作用是从nodejs执行一个shell命令,例子中使用它获取当前目录下所有文件("ls-lah"),然后当start请求时将文件信息输出到浏览器。执行该例子,浏览器输出“empty”。原因在于,nodejs是同步执行,而为了非阻塞,exec()使用了回调函数,回调函数作为参数传递给exec(),而exec()是异步操作,即当他还没来得及执行回调,nodejs的同步性致使nodejs执行了exec()的下一个语句,这时候content并没有等来exec()的赋值,因此他还是“empty”。这和javascript中的同步异步很相像,每当需要执行ajax,并且需要ajax的结果时,我们将下一步的代码放在ajax执行成功时的回调里。
非阻塞方式对请求进行响应
我们可以采用值传递的方式将请求处理函数返回的内容再回传给http服务器。上述方式都是将请求处理函数的结果返回给http服务器,而另一种方式是将服务器传递给内容,即将response对象传递给请求处理程序,程序随后采用该对象上的方法对对请求进行响应。
server.js
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(route,handle){
5 http.createServer(function(req,res){
6 var pathname = url.parse(req.url).pathname;
7 console.log('http request for '+pathname+' recieved');
8
9 route(handle,pathname,res);
10
11 }).listen(3000,'127.0.0.1');
12
13 console.log('http server start on port 3000');
14 }
15
16 exports.serverStart = serverStart;
以上将server.js中有关response的函数调用全部移除,将response对象传给route。
router.js
1 function route(handle,pathname,response){
2 console.log('about to route a request for'+pathname);
3
4 if(typeof handle[pathname] === 'function'){
5 return handle[pathname](response);
6 }
7 else{
8 console.log('no request handler found for'+pathname);
9 response.writeHead(404,{"Content-Type":"text/plain"});
10 response.write("404 not found!");
11 response.end();
12 }
13 }
14
15 exports.route = route;
requestHandlers.js
1 var exec = require("child_process").exec;
2
3 function start(response){
4 console.log("request handler 'start' was called");
5
6 exec("ls-lah",function(error,stdout,stderr){
7 response.writeHead(200,{"Content-Type":"text/plain"});
8 response.write(stdout);
9 response.end();
10 });
11
12 }
13
14 function upload(response){
15 console.log("request handler 'upload' was called");
16
17 response.writeHead(200,{"Content-Type":"text/plain"});
18 response.write("hello upload");
19 response.end();
20 }
21
22 exports.start = start;
23 exports.upload = upload;
处理程序接收response对象,由该对象做出直接响应。在此编译,打开浏览器请求,“localhost:3000/start”不会对"localhost:3000/upload"造成阻塞。
更有用的场景
处理post请求
1 var exec = require("child_process").exec;
2
3 function start(response){
4 console.log("request handler 'start' was called");
5
6 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post">'+'<textarea name="text" rows="20" cols="50"></textarea>'+
7 '<input type="submit" value="submit"/>'+'</form></body></html>';
8
9 response.writeHead(200,{"Content-Type":"text/html"});
10 response.write(body);
11 response.end();
12
13 }
14
15 function upload(response){
16 console.log("request handler 'upload' was called");
17
18 response.writeHead(200,{"Content-Type":"text/plain"});
19 response.write("hello upload");
20 response.end();
21 }
22
23 exports.start = start;
24 exports.upload = upload;
以上是修改后的requestHandlers.js,运行后是个简单的表单,包括文本域和提交按钮。post数据有时候会很大,为使过程不阻塞,nodejs会将post数据拆分成很多很小的数据块,然后通过触发特定的事件,将这些小数据块传给回调函数。特定事件有data(表示新的小数据块到了)和end(表示所有数据块都已经接收完毕)。这时候我们需要告诉nodejs事件触发的时候调用哪些回调函数,通过什么方式告诉呢?在request对象上注册监听器(listener)来实现。获取所有来自请求端的数据并将数据传给应用层处理,是http服务器的事。所以直接在server里处理post数据,然后将最终的数据传给路由和请求处理器,让他们来进一步处理。
server.js
1 function serverStart(route,handle){
2 http.createServer(function(req,res){
3 var postData = "";
4 var pathname = url.parse(req.url).pathname;
5 console.log('http request for '+pathname+' recieved');
6
7 request.setEncoding("utf8");
8
9 request.addListener("data",function(postDataChunk){
10 postData += postDataChunk;
11 console.log('received post data chunk'+postDataChunk+".");
12 });
13
14 request.addListener("end",function(postDataChunk){
15 route(handle,pathname,res,postData);
16 });
17
18 }).listen(3000,'127.0.0.1');
19
20 console.log('http server start on port 3000');
21 }
22
23 exports.serverStart = serverStart;
上述代码做了3件事,首先设置接收数据格式为utf8,然后绑定data事件的监听器,用于接收每次传递的新数据块,复制给postData,最后将路由调用移到end中,确保数据接收完成在触发并且只触发一次。
requestHandlers.js
1 var querystring = require("querystring");
2 function start(response,postData){
3 console.log("request handler 'start' was called");
4
5 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post">'+'<textarea name="text" rows="20" cols="50"></textarea>'+
6 '<input type="submit" value="submit"/>'+'</form></body></html>';
7
8 response.writeHead(200,{"Content-Type":"text/html"});
9 response.write(body);
10 response.end();
11
12 }
13
14 function upload(response,postData){
15 console.log("request handler 'upload' was called");
16
17 response.writeHead(200,{"Content-Type":"text/plain"});
18 response.write("you are sent:"+querystring.parse(postData).text);
19 response.end();
20 }
21
22 exports.start = start;
23 exports.upload = upload;
通过querystring筛选出我们感兴趣的部分,以上就是关于post数据处理的内容。
处理文件上传
处理文件上传就是处理post数据,有时候麻烦的是细节处理。所以这里使用现成的方案,即外部模块node-formidable,用nmp命令安装:
nmp install formidable
该模块做的就是通过http post请求提交的表单,在nodejs中可以被解析。我们创建一个IncomingForm,它是对提交的表单的抽象表示,之后就可以用他来解析request对象,获取需要的字段数据。关于该模块具体信息及工作原理,其官网有实例。
现在的问题是保存在本地硬盘的内容如何显示在浏览器中。我们需要将其读取到服务器,使用fs模块完成。
1 var querystring = require("querystring"),
2 fs = require("fs");
3 function start(response,postData){
4 console.log("request handler 'start' was called");
5
6 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post">'+'<textarea name="text" rows="20" cols="50"></textarea>'+
7 '<input type="submit" value="submit"/>'+'</form></body></html>';
8
9 response.writeHead(200,{"Content-Type":"text/html"});
10 response.write(body);
11 response.end();
12
13 }
14
15 function upload(response,postData){
16 console.log("request handler 'upload' was called");
17
18 response.writeHead(200,{"Content-Type":"text/plain"});
19 response.write("you are sent:"+querystring.parse(postData).text);
20 response.end();
21 }
22
23 function show(response,postData){
24 console.log("request handler 'show' was called");
25 fs.readFile("/tmp/test.png","binary",function(error,file){
26 if(error){
27 response.writeHead(500,{"Content-Type":"text/plain"});
28 response.write(error+"\n");
29 response.end();
30 }else{
31 response.writeHead(200,{"Content-Type":"image/png"});
32 response.write(file,"binary");
33 response.end();
34 }
35 });
36 }
37
38 exports.start = start;
39 exports.upload = upload;
40 exports.show = show;
将其添加到index.js的路由映射表中:
1 var server = require("./server");
2 var router = require("./router");
3 var requestHandlers = require("./requestHandlers");
4
5 var handler = {};
6 handler['/'] = requestHandlers.start;
7 handler['/start'] = requestHandlers.start;
8 handler['/upload'] = requestHandlers.upload;
9 handler['/show'] = requestHandlers.show;
10
11 server.serverStart(router.route,handler);
编译,浏览器请求即可看见图片。
最后,
需要在/start表单添加文件上传元素
将formidable整合到upload中用于将上传的图片保存到指定路径
将上传的图片内嵌到/upload url输出的html中
第一项,移除此前的文本区,添加上传组件和“multipart/form-data”编码类型:
1 var querystring = require("querystring"),
2 fs = require("fs");
3 function start(response,postData){
4 console.log("request handler 'start' was called");
5
6 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post" enctype="multipart/form-data">'+
7 '<input type="file" name="upload"/><input type="submit" value="upload file">'+'</form></body></html>';
8
9 response.writeHead(200,{"Content-Type":"text/html"});
10 response.write(body);
11 response.end();
12
13 }
14
15 function upload(response,postData){
16 console.log("request handler 'upload' was called");
17
18 response.writeHead(200,{"Content-Type":"text/plain"});
19 response.write("you are sent:"+querystring.parse(postData).text);
20 response.end();
21 }
22
23 function show(response,postData){
24 console.log("request handler 'show' was called");
25 fs.readFile("/tmp/test.png","binary",function(error,file){
26 if(error){
27 response.writeHead(500,{"Content-Type":"text/plain"});
28 response.write(error+"\n");
29 response.end();
30 }else{
31 response.writeHead(200,{"Content-Type":"image/png"});
32 response.write(file,"binary");
33 response.end();
34 }
35 });
36 }
37
38 exports.start = start;
39 exports.upload = upload;
40 exports.show = show;
1 var querystring = require("querystring"),
2 fs = require("fs");
3 function start(response,postData){
4 console.log("request handler 'start' was called");
5
6 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post" enctype="multipart/form-data">'+
7 '<input type="file" name="upload"/><input type="submit" value="upload file">'+'</form></body></html>';
8
9 response.writeHead(200,{"Content-Type":"text/html"});
10 response.write(body);
11 response.end();
12
13 }
14
15 function upload(response,postData){
16 console.log("request handler 'upload' was called");
17
18 response.writeHead(200,{"Content-Type":"text/plain"});
19 response.write("you are sent:"+querystring.parse(postData).text);
20 response.end();
21 }
22
23 function show(response,postData){
24 console.log("request handler 'show' was called");
25 fs.readFile("/tmp/test.png","binary",function(error,file){
26 if(error){
27 response.writeHead(500,{"Content-Type":"text/plain"});
28 response.write(error+"\n");
29 response.end();
30 }else{
31 response.writeHead(200,{"Content-Type":"image/png"});
32 response.write(file,"binary");
33 response.end();
34 }
35 });
36 }
37
38 exports.start = start;
39 exports.upload = upload;
40 exports.show = show;
这时候我们需要在upload中对请求中的上传文件进行处理,这样的话需要将request传给node-formidable的form-parse函数。由于nodejs不会对数据作缓冲,于是必须将request对象传入。
server.js:
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(route,handle){
5 http.createServer(function(req,res){
6
7 var pathname = url.parse(req.url).pathname;
8 console.log('http request for '+pathname+' recieved');
9
10 route(route,handle,res,req);
11
12 }).listen(3000,'127.0.0.1');
13
14 console.log('http server start on port 3000');
15 }
16
17 exports.serverStart = serverStart;
1 var http = require('http');
2 var url = require('url');
3
4 function serverStart(route,handle){
5 http.createServer(function(req,res){
6
7 var pathname = url.parse(req.url).pathname;
8 console.log('http request for '+pathname+' recieved');
9
10 route(route,handle,res,req);
11
12 }).listen(3000,'127.0.0.1');
13
14 console.log('http server start on port 3000');
15 }
16
17 exports.serverStart = serverStart;
router.js:
1 function route(handle,pathname,response,request){
2 console.log('about to route a request for'+pathname);
3
4 if(typeof handle[pathname] === 'function'){
5 return handle[pathname](response,request);
6 }
7 else{
8 console.log('no request handler found for'+pathname);
9 response.writeHead(404,{"Content-Type":"text/plain"});
10 response.write("404 not found!");
11 response.end();
12 }
13 }
14
15 exports.route = route;
1 function route(handle,pathname,response,request){
2 console.log('about to route a request for'+pathname);
3
4 if(typeof handle[pathname] === 'function'){
5 return handle[pathname](response,request);
6 }
7 else{
8 console.log('no request handler found for'+pathname);
9 response.writeHead(404,{"Content-Type":"text/plain"});
10 response.write("404 not found!");
11 response.end();
12 }
13 }
14
15 exports.route = route;
将上传和重命名的操作放在一起:
1 var querystring = require("querystring"),
2 fs = require("fs"),
3 formidable = require("formidable");
4 function start(response){
5 console.log("request handler 'start' was called");
6
7 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post" enctype="multipart/form-data">'+
8 '<input type="file" name="upload"/><input type="submit" value="upload file">'+'</form></body></html>';
9
10 response.writeHead(200,{"Content-Type":"text/html"});
11 response.write(body);
12 response.end();
13
14 }
15
16 function upload(response,postData){
17 console.log("request handler 'upload' was called");
18
19 var form = new formidable.IncomingForm();
20 form.parse(request,function(error,fields,files){
21 fs.renameSync(file.upload.path,"/tmp/test.png");
22 response.writeHead(200,{"Content-Type":"text/html"});
23 response.write("image:</br>");
24 response.write("<image src='/show'/>");
25 response.end();
26 });
27
28 }
29
30 function show(response,postData){
31 console.log("request handler 'show' was called");
32 fs.readFile("/tmp/test.png","binary",function(error,file){
33 if(error){
34 response.writeHead(500,{"Content-Type":"text/plain"});
35 response.write(error+"\n");
36 response.end();
37 }else{
38 response.writeHead(200,{"Content-Type":"image/png"});
39 response.write(file,"binary");
40 response.end();
41 }
42 });
43 }
44
45 exports.start = start;
46 exports.upload = upload;
47 exports.show = show;
1 var querystring = require("querystring"),
2 fs = require("fs"),
3 formidable = require("formidable");
4 function start(response){
5 console.log("request handler 'start' was called");
6
7 var body = '<html>'+'<head>'+'<body>'+'<form action="/upload" method="post" enctype="multipart/form-data">'+
8 '<input type="file" name="upload"/><input type="submit" value="upload file">'+'</form></body></html>';
9
10 response.writeHead(200,{"Content-Type":"text/html"});
11 response.write(body);
12 response.end();
13
14 }
15
16 function upload(response,postData){
17 console.log("request handler 'upload' was called");
18
19 var form = new formidable.IncomingForm();
20 form.parse(request,function(error,fields,files){
21 fs.renameSync(file.upload.path,"/tmp/test.png");
22 response.writeHead(200,{"Content-Type":"text/html"});
23 response.write("image:</br>");
24 response.write("<image src='/show'/>");
25 response.end();
26 });
27
28 }
29
30 function show(response,postData){
31 console.log("request handler 'show' was called");
32 fs.readFile("/tmp/test.png","binary",function(error,file){
33 if(error){
34 response.writeHead(500,{"Content-Type":"text/plain"});
35 response.write(error+"\n");
36 response.end();
37 }else{
38 response.writeHead(200,{"Content-Type":"image/png"});
39 response.write(file,"binary");
40 response.end();
41 }
42 });
43 }
44
45 exports.start = start;
46 exports.upload = upload;
47 exports.show = show;
好,编译,重启浏览器。选择本地图片,上传并显示!
结构图如下:
该实例有关的技术点:
服务器端javascript
函数式编程
阻塞与非阻塞
单线程
回调
事件
nodejs模块
没有介绍到的还有数据库操作、单元测试、开发外部模块等。
注:本文摘抄自《nodejs入门》
nodejs上传图片并显示的例子的更多相关文章
- COS上传图片和显示图片
写这篇文章之前,我也是刚刚实现COS上传和显示图片.我百度了好多相关文章,COS上传图片成功的文章不少,上传后显示图片的文章几乎没有.于是写一篇记录下. COS上传图片推荐链接:https://blo ...
- Js实现input上传图片并显示缩略图
用这个方法就可以很方便快捷的实现上传图片并显示缩略图的效果: FileReader 的 readAsDataURL() 先创建一个img标签,再用 fileReader 把input文件的赋值到img ...
- nodeJs学习过程之一个图片上传显示的例子
目标 1. 在浏览器地址栏输入“http://demos/start”,进入欢迎页面,页面有一个文件上传表单: 2. 选择一张图片并提交表单,文件被上传到"http://demos/uplo ...
- javaweb中上传图片并显示图片,用我要上传课程信息(里面包括照片)这个例子说明
原理: 从客户端上传到服务器 照片——文件夹——数据库 例如:桌面一张照片,在tomacat里创建upload文件夹,把桌面照片上传到upload文件夹里,并且把照片的 ...
- nodejs - 1)上传图片 ,并显示 , 2)模块 formidable
1.代码: 1-1: 入口文件: index.js var server = require('./server'); var router = require("./router" ...
- springmvc上传图片并显示图片--支持多图片上传
实现上传图片功能在Springmvc中很好实现.现在我将会展现完整例子. 开始需要在pom.xml加入几个jar,分别是: <dependency> <groupId>comm ...
- springmvc上传图片并显示--支持多图片上传
实现上传图片功能在Springmvc中很好实现.现在我将会展现完整例子. 开始需要在pom.xml加入几个jar,分别是: <dependency> <groupId>comm ...
- 写了一个简单的NodeJS实现的进程间通信的例子
1. cluster介绍 大家都知道nodejs是一个单进程单线程的服务器引擎,不管有多么的强大硬件,只能利用到单个CPU进行计算.所以,有人开发了第三方的cluster,让node可以利用多核CPU ...
- 使用nodejs搭建服务器显示HTML页面
首先安装express 在命令行输入:npm install express -g 安装完成后可以查看安装情况:npm ls -g 然后创建server.js文件 var express = requ ...
随机推荐
- 网站中的专题页或者tag聚合页的权重不错
一.据最近的一些观察,觉得网站中的专题页或者tag聚合页的权重不错,因此多给网站制作一些专题页面,不仅有利于聚合站内的文章,更是绝对的原创内容,应该会受到百度的青睐.简评:关于权重的讨论,这篇无疑是很 ...
- Android中的单位及测试相关概念
android中的单位: in 英寸 pt 点距 px 像素 dp(dip) 密度无关的像素单位,自适应device屏幕的比例,通常涉及长宽高时采用 sp 与范围无关的像素单位,通常在设置字体大小时 ...
- 学习ThinkPHP-1
ThinkPHP 自建路由 关于文件关联 当在Applicatin\Home\Controller文件夹下建立一个控制器时如LoginController.class.php 在此文件夹下还有一个默认 ...
- Oracle Client Language Problem
If you execute SP in the Oracle client and got the error like this: oracle.xdo.XDOException: oracl ...
- boost之function
boost中function是对函数指针和函数对象的进行封装的模板类. 定义示例:function<int()> func生成一个空的对象,表示函数参数个数为零,返回类型为int. #in ...
- matrix_last_acm_5
password 123 A http://acm.hust.edu.cn/vjudge/contest/view.action?cid=97960#problem/A 题意:给国王生日可能区间[a, ...
- 12 高性能I/O框架库Libevent
这里不讲Libevent库的具体内容了,从宏观上对I/O库整体做个介绍 Linux服务器程序必须处理三类事件:I/O事件,信号和定时事件 统一事件源:统一处理这三类事件既能使代码简单易懂,又能避免一些 ...
- WinHex分析PE格式(2)&& 如何手动添加区段并运行区段
由于这次文章内容比较多 所以写成DOC文档 为了复习所学的知识,我在原本的软件里试者手动加入区段 ,并写给大家分享,还试试者用LordPE加区段发现竟然失败了, 还是自己动手比较实在,完美运行. 利用 ...
- 《深入浅出JavaScript》
第一章JS入门 第二章数据和判定常用的转义序列\b 回退 \f换页 \n换行 \r回车 \t制表符 \'单引 \"双引 \\反斜乘除求余的优先级相同,从左向右执行string对象indexO ...
- Codeforces Round #242 (Div. 2) C题
题目链接:http://codeforces.com/contest/424/problem/C, 想来一个小时,就是做不出,都做出来了,悲剧! 分析:我们知道交换异或的顺序不影响答案! 然后就是求t ...