Nodejs學(xué)習(xí)第4天

之前我學(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)容了。如下:

Screenshot from 2016-10-14 23-41-40.png

之后又學(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)糾正! 謝謝~~ #

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Node.js是目前非?;馃岬募夹g(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    w_zhuan閱讀 3,721評(píng)論 2 41
  • Node.js是目前非?;馃岬募夹g(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    Myselfyan閱讀 4,191評(píng)論 2 58
  • JavaScript 資源大全中文版很多程序員應(yīng)該記得 GitHub 上有一個(gè) Awesome - XXX 系列的...
    wwmin_閱讀 3,650評(píng)論 1 91
  • 以為把耳機(jī)聲音開(kāi)大到除了音樂(lè)什么都聽(tīng)不見(jiàn) 就能聽(tīng)不見(jiàn)所有 還真是 。
    荒荒荒荒荒荒閱讀 141評(píng)論 0 0
  • 記得今天早晨一醒來(lái),看到被子上的血跡,還好,我不是女生,不用懷疑別的。是的,又流鼻血了。數(shù)了數(shù),應(yīng)該有一個(gè)多月的樣...
    Mr_Zoul閱讀 215評(píng)論 0 0

友情鏈接更多精彩內(nèi)容