2014年10月29日 星期三

『Node.js』介紹 middleware 應用與開發

從我們前幾篇用到 express web framework 框架的時候,express 就已經內建啟用 middleware 的概念,可以利用中間層的這個部分做一些效果,接下來本章節就來介紹  middleware 。首先我們先建立好一個 express web framework 框架

建立 express 的指令是:

$express -e nodejs-middleware

並且打開 app.js 檔案

var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);

/// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

/// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});


module.exports = app;

從上面建立的  express 框架可以看到這裡用了許多的 app.use 的方法,包含靜態檔案、body 解析器、路由機制。當預設 middleware 之後,每當瀏覽器收到連線要求的時候,middleware 就會被呼叫啟用。簡單來講 middleware 就像一個薄薄的一層過濾網

建立 middleware 

由於基本設定接已經有提供高效能的套件,其 express  所建立好的 middleware 設定之外,也可以自定撰寫 middleware 安排到基本設定流程當中,我們建立一個簡單的 middleware 功能,請在 app.js 安插以下程式:



一開始先建立一個 middleHandler ,其基本參數有  request, response, next,而  next方法 是代表交給下一個 middleware 繼續作處理,接著在建立 app.get ,我們預期要從瀏覽器  /test ㄙㄟ來做請求,第二個參數為 middleHandler function ,以及第三個 callback 函式



一開始從瀏覽器 localhost:3000/test 發送出去之後,會先進到 middleHandler ,所以會先顯示 **start** :: middle handler function ,然後遇到  next(); 之後再回到 app.get  繼續作處理,因此再將 **end** :: middle handler function 顯示,最後用了一個 res.send 方法將一個小字串文字直接輸出到瀏覽器上面。

下圖可看結果:




更多應用,下回待續... 


參考資料:
http://stephensugden.com/middleware_guide/
http://www.hacksparrow.com/how-to-write-midddleware-for-connect-express-js.html

『Node.js』基礎工具核心模組 util.inherits 實現原型繼承

在 js 的內建功能裡面如果有些不適合或無法滿足需求的時候,多半都要動手刻程式然後做到自己要的模組來呼叫方法。而 Node.js 提供了一個函數的集合,能夠比 js 更多的一些基本的處理,我們可以看到以下官方網站所提供 util 可用的方法。在本章節將介紹比較重要關注的方法


util.inherits 實現原型繼承

引用內建基礎工具  util,請在程式第一行寫 var util = require('util’);  方可使用工具的方法。在這邊我們介紹繼承的功能,也就是  util.inherits(constructor, superConstructor),在參數的第一個作為建構子,而第二參數為父建構子,直接來看程式的部分

function fnBase() {
     this.name = 'java';
     this.price = 250;

     this.getBookName = function() {
          console.log("getBookName: the book name is " + this.name);
     };
}

fnBase.prototype.showName = function(){
     console.log("showName: " + this.name);
};

fnBase.prototype.showPrice = function(){
     console.log("showPrice: " + this.price);
};

在這邊開始先建立了一個 fnBase 的物件,包含 name, price 屬性並且給予初始化值以及 getBookName 方法,而這個取得 book 的名稱。另外再多兩個 prototype 的原型方法,一個是 showName 以及 showPrice 方法,接著我們在建立一個物件

function Book() {
     this.name = "nodejs";
}

我們定義好基礎對象為 fnBase 之後,以及繼承 fnBook  的 Book 建構子的屬性 name 為 nodejs,我們在透過以下方法來塑造繼承關係

util.inherits(Book, fnBase);

接下來呼叫一下看看會有什麼變化,首先我們先建立 fnBase  的物件,在呼叫內部包含的方法,showName 及 getBookName

var obj = new fnBase();
obj.showName();
obj.getBookName();
console.log(obj);

其結果如下,可以看到呼叫的兩個方法皆有顯示答案




最後將 new fnBase() 換成  new Book() 看看,程式如下:

var book = new Book();
book.showName();
book.getBookName();
console.log(book);

Oops! 為什麼會出錯?結果居然只呼叫得到 showName, 卻無法取得  getBookName.




原因是因為 Book  只會繼承 fnBase 在原型 prototype 的函數,其建立的屬性與 getBookName 並不會被 Book 繼承。因此在繼承上的觀念則要特別注意了

參考資料:
http://nodejs.org/api/util.html
http://www.w3schools.com/js/js_object_prototypes.asp

『Node.js』讀取 markdown 檔案內容顯示在頁面上

繼上一篇完成讀取檔案的操作之後,本篇將介紹讀取  markdown 檔案內容顯示在頁面上面。

話說前頭,什麼是 markdown?

從 wiki 網站所說的,它是一種輕量級的標記語言,允許使用容易讀也容易寫的純文字的格式,最後轉換 xhtml, html 檔案,就有點像是一般電子郵件純文本的特性。可以從這個網址來 http://markdown.tw/ 學習每個元素的寫法。

node-markdown 實作

首先我們建立一個 express web framework 的專案,在這邊的樣板引擎是用 ejs ,因此下的指令是 

$express -e nodejs-fs-markdown

在根目錄底下建立一個 markdown 檔案,名為 book.md 的檔案,開啓 book.md 檔案後,我們任意打一些 markdown 的格式預備要來轉換  html 格式




接著重要我們要採用  node-markdown 的套件來安裝,詳見 https://www.npmjs.org/package/node-markdown ,安裝方式可使用

$npm install node-markdown 

其檔案結構會是:




請打開 app.js 檔案,我們要將 node-markdown 引入,因此宣告方式為:

var md = require("node-markdown").Markdown;

並且在 app.js 檔案裡面安插以下這段

app.get('/markdown', function(req, res){
    fs.readFile("./book.md", function (err, data) {
        if (err) {
            throw err;
        }

       //使用  md 方法將檔案內容轉行為 html 格式
        str = md(data.toString());
        console.log(str);

        //回應結果顯示在頁面上
        res.send(str) 
        res.end(); 
    });
});

在這邊使用了 /markdown 作為進入的網址,而這個網址主要是去解析 markdown 的檔案,在這個 function 下,我們還需要利用  fs 核心模組來讀取 book.md 檔案,請務必在宣告的地方加入  var fs = require("fs”); 

讀取的方式就使用  fs.readFile 方法,接著更重要的是再使用 md 方法將檔案內容轉換成  html 格式,最後,看一下結果如下,將會依照 markdown 的格式轉換




學習了這個工具,之後再撰寫 html 的檔案時,可以利用 markdown 的格式來寫,寫起來又輕鬆又好懂喔!
下集待續...

參考資料:
http://markdown.tw/
http://www.wikiwand.com/zh-tw/Markdown


『Node.js』核心模組檔案系統 fs

node.js  提供了檔案操作的模組,包含讀取、刪除、寫入、更名等等的檔案操作。其中 fs 模組他還提供了同步與非同步的方法來使用。他的方法名稱也相當好懂,如果是非同步那麼就 fs.readFile() ,同步的話就是 fs.readFileSync(),相當好區別。本章節將會介紹檔案系統的基本操作,如:

> 讀取檔案 fs.readFile
> 寫入檔案 fs.writeFile
> 附加檔案內容 fs.appendFile
> 更名檔案 fs.rename
> 刪除檔案 fs.unlink

首先我們先建立一個 nodejs-fs 目錄夾,預設檔案結構如下:


content.txt , test.txt 簡單預設寫一些內文,就可以進行以下的檔案系統相關操作:

在操作的宣告裡面,在 index.js 檔案,首先務必要檔案檔案系統模組

var fs = require(‘fs’);

接著我們就可以使用 fs 所提供的方法,方法可參考 http://nodejs.org/api/fs.html

讀取檔案 fs.readFile

var fs = require('fs’); //載入檔案系統模組
//讀取  content.txt 檔案內容
fs.readFile('content.txt', 'utf-8’, function(err, data){
     //若有錯誤就列印訊息
     if (err) {
          console.error(err);
     } else {

          //將檔案內容輸入
          console.log(data);
     }
});

寫入檔案 fs.writeFile

var data1 = "hello, ithome 鐵人賽”;
fs.writeFile(__dirname + '/content.txt', data1, function(err){
     if (err) {
          console.error(err)
     }
});

附加檔案內容 fs.appendFile

var data2 = "的主計林車修該自是";
fs.appendFile(__dirname + '/content.txt', data2, function(err){
     if (err) {
          console.error(err)
     }
});

更名檔案 fs.rename

var oldpath = "content2.txt";
var newpath = "content.txt";
fs.rename(oldpath, newpath, function(err){
     if (err)
          throw err;

       fs.stat('content.txt', function (err, stats) {
         if (err)
              throw err;

         //將檔案的狀態顯示出來
          // stats: {"dev":16777218,
         //      "mode":33204,
         //      "nlink":1,
         //      "uid":501,
         //      "gid":20,
         //      "rdev":0,"blksize":4096,
         //      "ino":33307834,
         //      "size":1254,
         //      "blocks":8,
         //      "atime":"2014-10-21T14:25:18.000Z",
         //      "mtime":"2014-10-21T14:24:56.000Z",
         //      "ctime":"2014-10-21T14:24:56.000Z"
         // }
        
         console.log('stats: ' + JSON.stringify(stats));
       });
});

刪除檔案 fs.unlink

fs.unlink('test.txt', function (err) {
  if (err) throw err;
  console.log('successfully deleted test.txt');
});

事實上檔案系統操作還有很多方法可以使用,可以看到我們

參考資料:
http://nodejs.org/api/fs.html

2014年10月20日 星期一

『Node.js』使用 nodemailer 套件透過 gmail 發送電子信箱

在上幾篇完成了 mysql  的 CRUD 的四大操作,本篇就來個輕鬆一點的應用,在這篇介紹使用 nodemailer 套件透過  gmail 來發送電子信箱,在安裝跟實作上也相當容易,我們透過 https://github.com/andris9/Nodemailer 來講解,在運用上也無需再重新打造輪子,學習如何使用即可。

在這邊先建立一個目錄夾 nodejs-nodemailer ,接著再指令將 package.json 建立起來 (本篇不著重在如何建立 package.json ,如需安裝操作請見 http://ithelp.ithome.com.tw/ironman7/app/article/all/recent/10158140 )。由於我們要安裝 nodemailer 套件,因此下指令

$npm install —save node mailer



其中 —save 會將 nodemailer 相依套件新增到 package.json 檔案裡的 dependencies 項目裡, 如下圖所示:



安裝完成之後,我們就可以來寫程式的部分了,可以看到上圖寫的 "start": “node email” ,在這邊我預定起始點是用 email.js ,因此請在根目錄下建立 email.js 檔案。我們初步的思考是這樣:

> 引入 nodemailer 套件
> 宣告發信的物件 (服務採用 gmail)
> 基本參數設定 (包含內文)
> 送出發信事件

我們直接看一下程式的部分:

//引用 nodemailer
var nodemailer = require('nodemailer');

//宣告發信物件
var transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
        user: ‘account@gmail.com',
        pass: ‘yourpassword'
    }
});

var options = {
    //寄件者
    from: ‘account1@gmail.com ',
    //收件者
    to: 'account2@gmail.com', 
    //副本
    cc: 'account3@gmail.com',
    //密件副本
    bcc: 'account4@gmail.com',
    //主旨
    subject: '這是 node.js 發送的測試信件', // Subject line
    //純文字
    text: 'Hello world2', // plaintext body
    //嵌入 html 的內文
    html: '

Why and How

The http://en.wikipedia.org/wiki/Lorem_ipsum" title="Lorem ipsum - Wikipedia, the free encyclopedia">Lorem ipsum
text is typically composed of pseudo-Latin words. It is commonly used as placeholder text to examine or demonstrate the visual effects of various graphic design. Since the text itself is meaningless, the viewers are therefore able to focus on the overall layout without being attracted to the text.',
    //附件檔案
    attachments: [ {
        filename: 'text01.txt',
        content: '聯候家上去工的調她者壓工,我笑它外有現,血有到同,民由快的重觀在保導然安作但。護見中城備長結現給都看面家銷先然非會生東一無中;內他的下來最書的從人聲觀說的用去生我,生節他活古視心放十壓心急我我們朋吃,毒素一要溫市歷很爾的房用聽調就層樹院少了紀苦客查標地主務所轉,職計急印形。團著先參那害沒造下至算活現興質美是為使!色社影;得良灣……克卻人過朋天點招?不族落過空出著樣家男,去細大如心發有出離問歡馬找事'
    }, {
        filename: ‘unnamed.jpg',
        path: '/Users/Weiju/Pictures/unnamed.jpg'
    }]
};

//發送信件方法
transporter.sendMail(options, function(error, info){
    if(error){
        console.log(error);
    }else{
        console.log('訊息發送: ' + info.response);
    }
});

可以看到引入的 nodemailer 的是使用 nodemailer.createTransport 物件先建立好發信的服務 service 為 Gmail,並且透過 auth 建立 gmail 登入的帳號密碼,接著宣告一下收件者 (to)、副本(cc)、密件副本(bcc)、寄件者(from),當然還有主旨 (Subject)、內文(text, html)、附件檔案(attachments)


最後發信結果,就如   package.json 上的 scripts.start 指令,下:
 
$node email



此時,發送結果會如訊息所說,我們再看看信件收到的樣子,由於附件傳送了兩筆,可以看到  unnamed.jpg  及 text01.txt  已經接收到了



其中 text01.txt  是直接在程式上面輸入純文字,我們來看看是否有真的寫入:



更多應用,稍等回來~

參考資料:

http://www.richyli.com/tool/loremipsum/
https://github.com/andris9/Nodemailer