이전 수업 전 학습에서는 다양한 모듈 사양 간의 연관성과 차이점에 대해 배웠습니다. 이번 섹션에서는 본격적으로 노드 학습을 시작합니다. 먼저 간단한 프로그램을 실행할 수 있는 http 서버를 구축하는 것부터 시작합니다.
가장 클래식한 hello world
. 먼저 코드를 저장하기 위해 server.js
을 생성합니다:
console.log( 'hello world' );
실행하려면 터미널에 node server.js
를 입력합니다:
node server.js
터미널 hello world라는 단어를 출력합니다. 하지만 노드 서버 프로그램은 항상 브라우저에서 액세스해야 합니다. 여기서는 노드와 함께 제공되는 http
모듈을 사용해야 합니다.
var http = require('http'); // 引入http模块// 创建http服务器// request : 从浏览器带来的请求信息// response : 从服务器返回给浏览器的信息http.createServer(function(request, response){ response.writeHead(200, {'content-type': 'text/plain'}); // 设置头部信息,输出text文本 response.write('hello world'); // 输出到页面中的信息 response.end(); // 返回结束}).listen(3000);console.log('server has started...');
여기에 다시 node server.js
를 입력합니다. 터미널에 서버가 시작되었습니다...라는 메시지가 터미널에 출력되어 서버가 생성되어 실행 중임을 나타냅니다. 그런 다음 브라우저에서 127.0.0.1:3000
을 방문합니다. hello world
페이지가 출력되는 것을 볼 수 있습니다.
지금은 페이지에 간단한 텍스트를 출력했지만 이제 사용자가 정보를 입력하고 제출할 수 있는 양식을 페이지에 표시하려고 합니다.
// server.js var http = require('http'); http.createServer(function(request, response){ var html = '<html>\ <head>\ <meta charset=UTF-8" />\ </head>\ <body>\ <form action="/" method="post">\ <p>username : <input type="text" name="username" /></p>\ <p>password : <input type="password" name="password" /></p>\ <p>age : <input type="text" name="age" /></p>\ <p><input type="submit" value="submit" name="submit" /></p>\ </form>\ </body>\ </html>'; response.writeHead(200, {'content-type': 'text/html'}); // 输出html头信息 response.write(html); // 将拼接的html字符串输出到页面中 response.end(); // 结束 }).listen(3000); console.log('server has started...');
server.js의 콘텐츠를 수정하고 다시 실행하세요.
node server.js
페이지를 새로 고친 후 텍스트 상자 3개와 제출 버튼 1개를 발견했습니다. 우리 프로그램은 페이지만 렌더링하고 다른 처리는 수행하지 않기 때문에 페이지에 데이터를 제출하면 현재 페이지가 새로 고쳐집니다.
참고: 노드의 코드를 수정할 때마다 다시 시작해야 합니다.
위 코드에서는 POST 방식을 사용했지만, 여기서는 먼저 GET
방식으로 제출된 데이터에 대해 살펴보겠습니다. 먼저 생각하지 마십시오. 데이터 보안은 get 메소드를 사용하여 제출된 양식 데이터를 얻는 방법을 배우고, post를 get으로 변경하고, 다시 실행하는 것입니다.
get 메소드를 사용하여 데이터를 제출하면 데이터가 URL 매개변수로 전달된다는 것을 알고 있으므로 URL의 매개변수를 구문 분석하여 데이터를 얻습니다. 여기서는 url
모듈의 메소드가 사용됩니다. 🎜 >
// server.js var http = require('http'), url = require('url'); http.createServer(function(request, response){ var html = '<html>\ <head>\ <meta charset=UTF-8" />\ </head>\ <body>\ <form action="/" method="get">\ <p>username : <input type="text" name="username" /></p>\ <p>password : <input type="password" name="password" /></p>\ <p>age : <input type="text" name="age" /></p>\ <p><input type="submit" value="submit" name="submit" /></p>\ </form>\ </body>\ </html>'; var query = url.parse( request.url, true ).query; if( query.submit ){ var data = '<p><a href="/">back</a></p>'+ '<p>username:'+query.username+'</p>'+ '<p>password:'+query.password+'</p>'+ '<p>age:'+query.age+'</p>'; response.writeHead(200, {'content-type': 'text/html'}); response.write(data); }else{ response.writeHead(200, {'content-type': 'text/html'}); response.write(html); } response.end(); // 结束 }).listen(3000); console.log('server has started...');
url.parse(request.url); result: Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: '?username=111113&password=123&age=122&submit=submit', query: 'username=111113&password=123&age=122&submit=submit', pathname: '/', path: '/?username=111113&password=123&age=122&submit=submit', href: '/?username=111113&password=123&age=122&submit=submit' }
url.parse(request.url, true);result:Url { ... query: { username: '111113', password: '123', age: '122', submit: 'submit' }, ... }
var query = url.parse( request.url, true ).query; /* { username: '111113', password: '123', age: '122', submit: 'submit'} */
// server.js var http = require('http'), querystring = require('querystring'); http.createServer(function(request, response){ var html = '<html>\ <head>\ <meta charset=UTF-8" />\ </head>\ <body>\ <form action="/" method="post">\ <p>username : <input type="text" name="username" /></p>\ <p>password : <input type="password" name="password" /></p>\ <p>age : <input type="text" name="age" /></p>\ <p><input type="submit" value="submit" name="submit" /></p>\ </form>\ </body>\ </html>'; if( request.method.toLowerCase()=='post' ){ var postData = ''; request.addListener('data', function(chunk){ postData += chunk; }); request.addListener('end', function(){ var data = querystring.parse(postData); console.log( 'postData: '+postData ); console.log(data); var s = '<p><a href="/">back</a></p>'+ '<p>username:'+data.username+'</p>'+ '<p>password:'+data.password+'</p>'+ '<p>age:'+data.age+'</p>'; response.writeHead(200, {'content-type': 'text/html'}); response.write(s); response.end(); }) }else{ response.writeHead(200, {'content-type': 'text/html'}); response.write(html); response.end(); } }).listen(3000); console.log('server has started...');
request.method.toLowerCase()=='post'
이벤트 내부에 기록됩니다. 비동기 작업이므로 반드시 데이터 출력이 완료된 후에만 실행할 수 있습니다. response.end()
end
response.end()
아아아아
因此我们使用query.parse
将postData解析为对象类型,以便获取提交过来的数据。
现在我们所有的逻辑都是在根目录下进行的,没有按照url区分,这里我们按照功能进行路由拆分。以上面的post请求为例,我们可以拆分为:页面初始化和form提交后的处理。
页面初始化:
// starter.js 页面初始化 function start(request, response){ var html = '<html>\ <head>\ <meta charset=UTF-8" />\ </head>\ <body>\ <form action="/show" method="post">\ <p>username : <input type="text" name="username" /></p>\ <p>password : <input type="password" name="password" /></p>\ <p>age : <input type="text" name="age" /></p>\ <p><input type="submit" value="submit" name="submit" /></p>\ </form>\ </body>\ </html>'; response.writeHead(200, {"Content-Type":"text/html"}); response.write( html ); response.end(); } exports.start = start;
展示获取的数据:
// uploader.js 展示获取的数据var querystring = require('querystring');function upload(request, response){ var postData = ''; request.addListener('data', function(chunk){ postData += chunk; }); request.addListener('end', function(){ var data = querystring.parse(postData); console.log( 'postData: '+postData ); console.log(data); var s = '<p><a href="/">back</a></p>'+ '<p>username:'+data.username+'</p>'+ '<p>password:'+data.password+'</p>'+ '<p>age:'+data.age+'</p>'; response.writeHead(200, {'content-type': 'text/html'}); response.write(s); response.end(); }) } exports.upload = upload;
然后在server.js中进行路由选择
// server.jsvar http = require('http'), url = require('url'); http.createServer(function(request, response){ var pathname = url.parse(request.url).pathname; console.log(pathname); response.end(); }).listen(3000);console.log('server has started...');
我们任意改变URL地址,会看到输出的每个地址的pathname(忽略/favicon.ico):
http://127.0.0.1:3000/ // 输出: / http://127.0.0.1:3000/show/ // 输出: /show/ http://127.0.0.1:3000/show/img/ // 输出: /show/img/ http://127.0.0.1:3000/show/?username=wenzi // 输出: /show/
因此我们就根据pathname进行路由,对路由进行方法映射:
// server.jsvar http = require('http'), url = require('url'), starter = require('./starter'), uploader = require('./uploader'); http.createServer(function(request, response){ var pathname = url.parse(request.url).pathname; var routeurl = { '/' : starter.start, '/show' : uploader.upload } if( typeof routeurl[pathname]=== 'function' ){ routeurl[pathname](request, response); }else{ console.log('404 not found!'); response.end(); } }).listen(3000);console.log('server has started...');
如果匹配到路由 /
,则执行 starter.start(request, response) ;如果匹配到路由 /show
,则执行 uploader.upload(request, response) 。如果都没匹配到,则显示404。
在上面我们已经能成功提交数据了,这里来讲解如何进行图片上传并显示。使用node自带的模块处理起来非常的麻烦,这里我们使用别人已经开发好的formidable
模块进行编写,它对解析上传的文件数据做了很好的抽象。
npm install formidable --save-dev
在starter.js中,我们添加上file控件:
// starter.js function start(request, response){ var html = '<html>\ <head>\ <meta charset=UTF-8" />\ </head>\ <body>\ <form action="/upload" method="post" enctype="multipart/form-data">\ <p>file : <input type="file" name="upload" multiple="multiple" /></p>\ <p><input type="submit" value="submit" name="submit" /></p>\ </form>\ </body>\ </html>'; response.writeHead(200, {"Content-Type":"text/html"}); response.write( html ); response.end(); } exports.start = start;
首先我们进行的是图片上传操作,首先我们要确保当前目录中存在tmp和img目录。在 uploader.js 中:
// uploader.jsvar formidable = require('formidable'), util = require('util'), fs = require('fs');function upload(request, response){ if( request.method.toLowerCase()=='post' ){ var form = new formidable.IncomingForm(); form.uploadDir = './tmp/'; form.parse(request, function(err, fields, files) { var oldname = files.upload.name, newname = Date.now() + oldname.substr(oldname.lastIndexOf('.')); fs.renameSync(files.upload.path, "./img/"+newname ); // 上传到 img 目录 response.writeHead(200, {'content-type': 'text/plain'}); response.write('received upload:\n\n'); response.end(util.inspect({fields: fields, files: files})); }); return; } } exports.upload = upload;
我们上传图片后跳转到upload路径,然后显示出相应的信息:
received upload: { fields: { // 其他控件,如input, textarea等 submit: 'submit'}, files:{ // file控件 upload:{ domain: null, _events: {}, _maxListeners: undefined, size: 5097, path: 'tmp\\upload_b1f7c3e83af224e9f3a020958cde5dcd', name: 'chrome.png', type: 'image/png', hash: null, lastModifiedDate: Thu Jan 12 2017 23:09:50 GMT+0800 (中国标准时间), _writeStream: [Object] } } }
我们再查看img目录时,就会发现我们刚才上传的照片了。
将图片上传到服务器后,怎样才能把图片显示在浏览器上呢。这里我们就使用到了fs
模块来读取文件,创建一个shower.js
来专门展示图片:
// shower.jsvar fs = require('fs'), url = require('url');function show(request, response){ var query = url.parse(request.url, true).query, imgurl = query.src; // 读取图片并进行输出 // 这里读取链接中的src参数,指定读取哪张图片 /show?src=1484234660592.png fs.readFile('./img/'+imgurl, "binary", function(err, file){ if(err) throw err; response.writeHead(200, {"Content-Type": "image/png"}); response.write(file, "binary"); response.end(); }) } exports.show = show;
然后在 server.js 中添加上 show 的路由映射:
var routeurl = { '/' : starter.start, '/upload' : uploader.upload, '/show' : shower.show // 添加 };
最后在 upload.js 中进行图片的引用:
form.parse(request, function(err, fields, files) { var oldname = files.upload.name, newname = Date.now() + oldname.substr(oldname.lastIndexOf('.')); fs.renameSync(files.upload.path, "./img/"+newname ); // 同步上传图片 response.writeHead(200, {'content-type': 'text/html'}); var s = '<p><a href="/">back</a></p><p><img src="/show?src='+newname+'" /></p>'; // 显示刚才的图片 response.write(s); response.end(); });
刚才学习了上传数据和上传图片,这里我们将其综合一下,拟定一个题目:“设定用户名密码,并上传头像”。希望可以自己实现一下。
在第2部分学习了GET和POST请求,那么在这里写一个简单json或jsonp接口应该不是什么难事儿了吧。
创建一个 inter.js :
// inter.jsvar url = require('url');function init(request, response){ if( request.method.toLowerCase()=='get' ){ var query = url.parse(request.url, true).query; var data = {"code":0, "msg":"success", "data":[{"username":"wenzi", "age":26}, {"username":"bing", "age":25}]}; if( query && query.callback ){ // jsonp response.end( query.callback + '(' + JSON.stringify(data) + ')' ); }else{ // json response.end( JSON.stringify(data) ); } } } exports.init = init;
在server中添加inter的引用和路由映射:
var routeurl = { '/' : starter.start, '/upload' : uploader.upload, '/show' : shower.show, '/inter' : inter.init // 添加};
然后对 http://127.0.0.1:3000/inter
进行json请求或jsonp请求即可。
这节还是写了不少的内容,最核心的就是讲解如何搭建一个简单的http服务器,进行数据和图片的提交与处理,在最后稍微讲了下接口的编写,后面有机会的话,会再具体讲解下接口的编写。