2012
Aug
19

第一篇,Node.js 串 Apache CGI

Node.js 接到從 Aapache CGI 的 Request 過來後,會把所有的 Header 參數都存到 process.env , 其中包含 NODE_PATH 、HTTP_HOST,HTTP_USER_AGENT,HTTP_ACCEPT、REQUEST_METHOD、QUERY_STRING...等

這篇主要目的是處理 GET 、 POST 、 COOKIE 、File Upload 這四種 HTTP Protocol 訊息傳輸的方式。

GET Param

GET 的參數會存在 process.env.QUERY_STRING,像這樣「 QUERY_STRING: 'account=test'」,所以只要將 QUERY_STRING 的內容做切割,就能夠很輕易的取出參數。

Get參數處理
  1. o.getGET = function (p) {/*{{{*/
  2. var q = p.env.QUERY_STRING;
  3. if(!q){return ;}
  4. var g = q.split(/&(?=[a-z])/);
  5.  
  6. var get = {};
  7. var reg = /([^=]+)=(.+)/i,t;
  8. var n = g.length;
  9. for(var i=0 ;i<n ;i++) {
  10. t = g[i].match(reg);
  11. if(t && t.length==3)
  12. get[t[1]] = t[2];
  13. }
  14. this.GET = get;
  15. }/*}}}*/
  16.  

POST Param

POST 的參數比起 GET 會比較複雜一點,POST 傳遞的參數長度是沒有限制,所以不能夠存在任何的變數中,否則會造成 buffer 溢出,會有安全上的疑慮,而 POST 的內容會存在 input buffer 中,必須透過讀取 buffer 的方式來操作。

透過讀取 /dev/stdin 的方式,將 input buffer 的資料讀進來「fs.readFileSync('/dev/stdin')」。

讀到 POST 的資料後,跟 GET 一樣使用 Regular Exp 的方式,將參數切割出來,存在 this.POST。

POST 參數處理
  1. /** param by method post**/
  2. o.getPOST = function(buff) {/*{{{*/
  3. if (!buff){return ; }
  4.  
  5. var g = buff.split(/&(?=[a-z])/);
  6.  
  7. var get = {};
  8. var reg = /([a-z0-9_\-]+)=(.+)/i,t;
  9. var n = g.length;
  10. for(var i=0 ;i<n ;i++) {
  11. t = g[i].match(reg);
  12. if(t && t.length==3)
  13. get[t[1]] = t[2];
  14. }
  15. this.POST = get;
  16.  
  17.  
  18. }/*}}}*/

COOKIE Param

瀏覽器傳過來的 COOKIE 的參數會存在 process.env.HTTP_COOKIE,像這樣「 HTTP_COOKIE: 'account=test; browser=ie'

正常的 cookie 的分割方式是使用 「; 」,一個分號,再加上一個空白,所以使用 RegExp 「/; /」就能快速的切割出來。

Cookie 處理
  1. o.getCookies = function () {
  2. if (!process.env.HTTP_COOKIE) {
  3. this.COOKIE={};
  4. return;
  5. }
  6. var cookieStr = process.env.HTTP_COOKIE;
  7. var cookieTmp = cookieStr.split(/; /i);
  8. var reg = /([a-z][^=]*)=(.+)/;
  9. var cookieList = {};
  10. var n = cookieTmp.length;
  11. for (var i=0; i<n;i++) {
  12. var t = cookieTmp[i].match(reg);
  13. cookieList[t[1]] = t[2];
  14. }
  15.  
  16. this.COOKIE = cookieList;
  17. }
  18.  
  19.  

File Upload

File Upload 的處理方式與 POST 有點像,File Upload 的資料一樣是存在 input buffer 裡,所以也是透過讀取「 /dev/stin」這個檔案。

在使用 File Upload 的 Form 表單中, HTML 都會出加上一個屬性 「enctype="multipart/form-data"

當 Form 有這個屬性時,檔案才會上傳成功,而加了 enctype 之後,原本 POST 的參數,也全部會變成 multipart/form-data 的上傳格式,不再適用於 POST 的處理,也就是說上一段的 POST Param 處理方式,是沒辦法接收到 「multipart」上傳的資料。

使用 multipart 上傳方式,在「process.env.CONTENT_TYPE」中會記錄一個字串 boundary , 這代表上傳內容切割的字串為何 ,例如 「boundary=------------------------------6815a6a6ad9e」,這代表上傳的參數必須使用「------------------------------6815a6a6ad9e」這一串字來做切割。

multipart 上傳的格式如下, 第一個是指上傳 key = account ,value = john ,第二個是指上傳的檔名為「test.txt」,內容是「test123」

Example
  1. ------------------------------6815a6a6ad9e
  2. Content-Disposition: form-data; name="account"
  3.  
  4. john
  5. ------------------------------6815a6a6ad9e
  6. Content-Disposition: form-data; name="file1"; filename="test.txt"
  7. Content-Type: application/octet-stream
  8.  
  9. test123

知道參數的儲存方式之後,就可以寫程式來實現檔案上傳囉,檔案上傳的程式碼較長,我就不貼了,請看 github

完整 HTTP procotol 處理的程式


回應 (Leave a comment)