之前我學(xué)習(xí)了使用Node.js實(shí)現(xiàn)一個(gè)簡(jiǎn)單的Server (見(jiàn)Nodejs學(xué)習(xí)第一天)這讓我想起了當(dāng)初學(xué)習(xí)java-web的時(shí)候,使用java #net 包下的Socket 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的類(lèi)似tomcat 的一個(gè)小Http服務(wù)器,如:
ServerSocket serverSocket = new ServerSocket(8080) ;
Socket socket = serverSocket.accept() ;
InputStream in = new FileInputStream(new File("/home/palm/myapps/node-study/oneself/server.js")) ;
OutputStream outputStream = socket.getOutputStream() ;
int len = 0 ;
byte[] b = new byte[1024] ;
while((len = in.read(b)) != -1) {
outputStream.write(b,0,len);
}
運(yùn)行上面的java 代碼, 一個(gè)沒(méi)有任何處理能力的簡(jiǎn)單Http服務(wù)器就可以使用了,上面代碼只是輸出了文件內(nèi)容,當(dāng)然也可以接收前端頁(yè)面?zhèn)鬟f的參數(shù)。訪問(wèn)http://localhost:8080/ 就可以看到輸出文件server.js的內(nèi)容了。如下:

之后又學(xué)習(xí)了使用內(nèi)置模塊來(lái)處理多請(qǐng)求分發(fā)的問(wèn)題,再次通過(guò)調(diào)整整體代碼架構(gòu)來(lái)適應(yīng)web多線程并發(fā)異步處理的問(wèn)題。
<em>
到這里,差不多就是node.js對(duì)http server支持的基礎(chǔ)的部分了. 我個(gè)人理解是node.js是又一個(gè)JavaScript運(yùn)行時(shí)環(huán)境,其實(shí)node官網(wǎng)也是這么解釋的,之前 JavaScript 之運(yùn)行在瀏覽器中,比如IE、Chomre、Firefox等。
誰(shuí)都知道瘟到死下的IE提供的 JavaScript運(yùn)行環(huán)境處處是坑,各種亂七八糟的非標(biāo)準(zhǔn)解釋?zhuān)瑢?dǎo)致 JavaScript在其下運(yùn)行各種問(wèn)題。兼容問(wèn)題層出不窮。
但是這些問(wèn)題在Node.js下不會(huì)再產(chǎn)生了,因?yàn)镹ode.js使用了chrome瀏覽器的V8引擎來(lái)解釋JavaScript代碼。在Node下只有一個(gè)標(biāo)準(zhǔn)就是遵循當(dāng)前ECMAScript標(biāo)準(zhǔn)來(lái)解釋執(zhí)行代碼,使用當(dāng)前ECMA支持語(yǔ)法就可以得到正確的結(jié)果。不會(huì)有一行代碼執(zhí)行結(jié)果各不相同。
</em>
Node.js? is a JavaScript runtime built on Chrome's V8 JavaScript engine. ...........
之前的node.js代碼向頁(yè)面輸出的都是一些簡(jiǎn)單的問(wèn)題,接下來(lái)的代碼會(huì)看起來(lái)更web一點(diǎn),因?yàn)榭梢杂杏脩?hù)交互了,如下:
將之前的dispatcher.js #start函數(shù)修改下,將一個(gè)簡(jiǎn)單的html代碼輸出并采用html數(shù)據(jù)格式解析,就像在進(jìn)入java-web學(xué)習(xí)的時(shí)候在學(xué)習(xí)jsp之前,就直接在servlet中write html代碼:
function start(res) {
console.log('call /start');
/**var process = require('child_process') ;
process.exec('cd /home/palm/ && find *',function(error,stdout,stdrr) {
//
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write(stdout) ;
res.end() ;
}) ;*/
var body = '<html>' +
'<head>' +
'<meta http-equiv="Content-Type" content="text/html; ' +
'charset=UTF-8" />' +
'</head>' +
'<body>' +
'<form action="/upload" method="post">' +
'<textarea name="text" rows="15" cols="50"></textarea>' +
'<input type="submit" value="提交" />' +
'</form>' +
'</body>' +
'</html>';
res.writeHead(200, {'Content-Type': 'text/html'}); //注意這里的內(nèi)容頭聲明
res.write(body);
res.end();
}
function upload(res) {
console.log('call /upload') ;
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write('call /upload') ;
res.end() ;
}
function root(res) {
console.log('call /') ;
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write('call /') ;
res.end() ;
}
exports.start = start ;
exports.upload = upload ;
exports.root = root ;
訪問(wèn) http://localhost:8081/start 就可以看到一個(gè)可以提交的簡(jiǎn)單表單,然后修改下/upload 來(lái)響應(yīng)這個(gè)表單的請(qǐng)求(上述輸出html提交路徑是/upload).
在/upload中一定需要采用異步處理機(jī)制,否則就產(chǎn)生阻塞了,所以這里需要進(jìn)行適當(dāng)?shù)恼{(diào)整。這里node采用了一個(gè)特定的事件 --- data事件用來(lái)處理數(shù)據(jù)接收 以及end事件來(lái)標(biāo)識(shí)數(shù)據(jù)接收完畢。根據(jù)node異步實(shí)現(xiàn)機(jī)制 ---- 事件輪詢(xún) , 事件node已經(jīng)提供了,剩下的需要我們提供對(duì)應(yīng)事件觸發(fā)后該做什么,也就是回調(diào)函數(shù)。所以只需要將這兩個(gè)回調(diào)函數(shù)提供給node就可以了。
因?yàn)檫@兩個(gè)事件都是發(fā)生在請(qǐng)求服務(wù)的過(guò)程中,所以把這兩個(gè)事件注冊(cè)到request對(duì)象上就顯得很合理了,如:
//server.js
//導(dǎo)入http 和 url模塊 類(lèi)似java的 Map\List等工具類(lèi)
var http = require('http'),
url = require('url') ;
//編寫(xiě)服務(wù)啟動(dòng)函數(shù),這里的參數(shù)稍后解釋
//function start(handle,route) {
function start(hander,route) {
//請(qǐng)求處理函數(shù),就是第一天學(xué)習(xí)的箭頭函數(shù),這里不再是一個(gè)匿名函數(shù)
function onRequest(req,res) {
//這里通過(guò)url模塊提供函數(shù) parse獲得請(qǐng)求方法,詳細(xì)可以參考node官方網(wǎng)站document說(shuō)明
var pathName = url.parse(req.url).pathname ;
console.log('request path ',pathName) ;
var postData = '' ;
req.setEncoding("utf8");
req.addListener('data',function(postDataChunk){
//
postData = postDataChunk ;
}) ;
//end
req.addListener('end',function(){
//
route(pathName,hander,res,postData) ;
}) ;
//dispatcher
//route(pathName,hander,res) ;
}
http.createServer(onRequest).listen(8081) ;
console.log('server has started.') ;
}
//將函數(shù)start函數(shù)導(dǎo)出為一個(gè)模塊
//export
exports.start = start ;
//dispatcher.js
function start(res,postData) {
console.log('call /start');
/**var process = require('child_process') ;
process.exec('cd /home/palm/ && find *',function(error,stdout,stdrr) {
//
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write(stdout) ;
res.end() ;
}) ;*/
var body = '<html>' +
'<head>' +
'<meta http-equiv="Content-Type" content="text/html; ' +
'charset=UTF-8" />' +
'</head>' +
'<body>' +
'<form action="/upload" method="post">' +
'<textarea name="text" rows="15" cols="50"></textarea>' +
'<input type="submit" value="提交" />' +
'</form>' +
'</body>' +
'</html>';
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(body);
res.end();
}
function upload(res,postData) {
console.log('call /upload') ;
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write(postData) ;
res.end() ;
}
function root(res,postData) {
console.log('call /') ;
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write('call /') ;
res.end() ;
}
exports.start = start ;
exports.upload = upload ;
exports.root = root ;
//router.js
function route(path,handle,res,postData) {
console.log('route path ',path) ;
var fun = handle[path] ;
if(typeof fun === "function") {
fun.call(null,res,postData) ;
}else {
console.log('unknown path.') ;
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write('404 Unknown path') ;
res.end() ;
}
}
exports.route = route ;
//index.js 不用改變
重啟服務(wù),訪問(wèn) http://localhost:8081/start 輸入在文本域內(nèi)輸入內(nèi)容,點(diǎn)擊提交 可以看到頁(yè)面條裝到 http://localhost:8081/upload 并輸出剛才錄入的內(nèi)容。
大概的數(shù)據(jù)流轉(zhuǎn)如下:
當(dāng)我點(diǎn)擊頁(yè)面提交按鈕后,將請(qǐng)求/upload 經(jīng)過(guò)server.js #start函數(shù) 通過(guò)data 事件的回調(diào)函數(shù)獲取到頁(yè)面錄入內(nèi)容,然后數(shù)據(jù)接收完畢后觸發(fā)end 事件,后通過(guò)end事件回調(diào)函數(shù)直接將此數(shù)據(jù)交給了/upload 方法,后又輸出到頁(yè)面。
如果提交中文內(nèi)容會(huì)發(fā)現(xiàn)跳轉(zhuǎn)到'/upload'頁(yè)面顯示的并不是我們之前輸入的內(nèi)容,是因?yàn)樵?upload中向頁(yè)面write內(nèi)容并不只是我們輸入的,所以這里需要使用Node內(nèi)置模塊querystring來(lái)獲取到之前頁(yè)面輸入的內(nèi)容:
function upload(res,postData) {
var querystring = require('querystring') ;
console.log('call /upload') ;
res.writeHead(200,{'Content-Type':'text/plain'}) ;
res.write(querystring.parse(postData).text) ; //通過(guò)querystring獲取text
res.end() ;
}
以上就是一個(gè)簡(jiǎn)單的Node.js對(duì)Post請(qǐng)求的處理結(jié)構(gòu),今天的學(xué)習(xí)就到這里啦,以上代碼或?qū)ode.js的理解有錯(cuò)誤的地方,懇請(qǐng)糾正! 謝謝~~ #