在上節的課前學習中,我們了解了一下不同模組規範之間的聯繫與區別。本節我們正式開始node的學習,首先我們先從建立一個http伺服器,能運行簡單的程式開始說起。
1. hello world
最經典的hello world
。首先我們建立一個server.js
來保存我們的程式碼:
console.log( 'hello world' );
在終端輸入node server.js
運行:
node server.js
終端就會輸出 的字樣。可是我們一個node伺服器程序,總是要在瀏覽器上訪問的呀,這裡就要用到node裡自帶的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...');
運行,終端機裡會有輸出server has started…
的字樣,表示伺服器已創建並正在運行,然後我們在瀏覽器上訪問127.0.0.1:3000,就可以看到頁面中輸出了hello world
。 2. form表單
剛才我們只是在頁面中輸出了一段簡單的文本,現在我們要在頁面中呈現一個表單,可以讓用戶輸入資訊並進行提交:
// 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...');
node server.js
我們每次修改node中的任何程式碼後,都要重新啟動。 2.1 取得表單GET方式提交的資料
我們上面的程式碼中使用的是POST方式,不過這裡要先討論使用
GET方式提交過來的數據,我們先不考慮資料的安全性,只是學習如何取得使用get方式提交過來的form表單數據,將post改為get,重新運行。 我們知道,使用get方式提交數據,會將數據作為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是用來解析URL字串的,並且傳回解析後的URL物件。若我們只輸出一下url.parse(request.url) :
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' }
如果將第2個參數設為true,則會將返回結果中的query屬性解析為一個對象,其他屬性不變;預設值為false ,即query屬性是一個字串:
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'} */
現在我們使用post方式來提交資料。因為POST請求一般都比較「重」 (使用者可能會輸入大量的內容),如果用阻塞的方式來處理處理,必然會導致使用者操作的阻塞。因此node將post資料拆分為許多小的資料塊,然後透過data事件(表示新的小資料塊到達了)和end事件傳遞這些小資料塊(表示所有的資料都已經接收完畢)。 所以,我們的思路應該是:在data事件中取得資料塊,在end事件中操作資料。
// 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...');
- 不再引入url模組, 改用引入querystring模組。因為我們不再對URL進行操作了,也沒必要引入了;
- 使用
- request.method.toLowerCase()=='post'
判斷當前是否有資料提交;
data 在data事件中進行資料的拼接,在end事件中進行的處理; - response.end()
寫在了
end
事件內部,因為end事件是非同步操作,因此必須得資料輸出完成之後才能執行response .end()
我們在控制台中可以看出,postData是這樣的一個字串:
'username=123&password=123&age=23&submit=submit';
因此我们使用query.parse
将postData解析为对象类型,以便获取提交过来的数据。
3. 路由
现在我们所有的逻辑都是在根目录下进行的,没有按照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。
4. 图片上传并显示
在上面我们已经能成功提交数据了,这里来讲解如何进行图片上传并显示。使用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;
4.1 图片上传
首先我们进行的是图片上传操作,首先我们要确保当前目录中存在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目录时,就会发现我们刚才上传的照片了。
4.2 图片显示
将图片上传到服务器后,怎样才能把图片显示在浏览器上呢。这里我们就使用到了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="/static/imghwm/default1.png" data-src="/show?src='+newname+'" class="lazy" / alt="從0到1學習node(二)建造http伺服器" ></p>'; // 显示刚才的图片
response.write(s);
response.end();
});
5. 综合
刚才学习了上传数据和上传图片,这里我们将其综合一下,拟定一个题目:“设定用户名密码,并上传头像”。希望可以自己实现一下。
6. 接口的实现
在第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请求即可。
7. 总结
这节还是写了不少的内容,最核心的就是讲解如何搭建一个简单的http服务器,进行数据和图片的提交与处理,在最后稍微讲了下接口的编写,后面有机会的话,会再具体讲解下接口的编写。

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器