標籤:

node.js教程7--KOA入門&發送郵件

JavaScript 標準參考教程(alpha)

Koa快速入門教程(一)

Koa 是由 Express 原班人馬打造的,致力於成為一個更小、更富有表現力、更健壯的 Web 框架,採用了asyncawait的方式執行非同步操作。

Koa有v1.0與v2.0兩個版本,隨著node對asyncawait的支持,Koa2的正式發布,本文Koa均指Koa2

如果你還不熟悉async函數可查閱阮大的ECMAScript 6 入門

這是一篇從零開始的簡易教程,話不多說,先來快速開始:hello world!

一、快速開始

1.1 開發環境

Koa 依賴 node v7.6.0 或 ES2015及更高版本和 async 方法支持,你可以使用自己喜歡的版本管理器快速安裝支持的 node 版本

$ node -vnv8.9.1n

如果你的版本號小於v7.6.0,請自行升級。如使用nvm

在確認好環境後,我們就可以新建一個項目,在裡面自由操練了

$ mkdir KoaTutorial && cd KoaTutorialnn$ npm i koa --saven

1.2 必修的 hello world 應用:

const Koa = require(koa);nconst app = new Koa();nnapp.use(async ctx => {n ctx.body = Hello World;n});nnapp.listen(3000);n

打開瀏覽器,訪問 localhost:3000/,你會看到那可愛的Hello World。就是這麼簡單的幾行代碼,我們就起了一個HTTP服務,

來來看看這個hello world程序,其中前兩行和後一行是架設一個 HTTP 服務。中間的則是對用戶訪問的處理。ctx則是Koa所提供的Context對象(上下文),ctx.body=則是ctx.response.body=的alias(別名),這是響應體設置的API。

1.3 Context 對象

Koa Context 將 node 的 requestresponse 對象封裝到單個對象中,為編寫 Web 應用程序和 API 提供了許多有用的方法。上例的ctx.body = 即是發送給用戶內容,它是ctx.response.body的簡寫*(更多請查閱官網)*。ctx.response代表 HTTP Response。ctx.request代表 HTTP Request。

二、路由(URL處理)

2.1 手動實現簡易路由

koa是個極簡的web框架,簡單到連路由模塊都沒有配備,我們先來可以根據ctx.request.url或者ctx.request.path獲取用戶請求的路徑,來實現簡單的路由。

const Koa = require(koa);nconst app = new Koa();nnapp.use(async ctx => {n let _html = 404 NotFoundn switch (ctx.url) {n case /:n _html = <h1>Index</h1>;n break;n case /adout:n _html = <h1>About</h1>;n break;n case /hello:n _html = <h1>world</h1>;n break;n default:n break;n }n ctx.body = _html;n});nnapp.listen(3000);n

運行這段代碼,訪問http://localhost:3000/hello將看見world,訪問http://localhost:3000/about將看見返回about,訪問http://localhost:3000將看見Index。是不是很有成就感…但是這也太麻煩了吧。如果依靠`ctx.request.url`去手動處理路由,將會寫很多代碼,這時候就需要對應的路由中間件來對路由進行控制: koa-router

2.2 使用koa-router中間件

簡單說,中間件(middleware)就是處理HTTP請求的函數。它最大的特點就是,一個中間件處理完,再傳遞給下一個中間件。App實例在運行過程中,會調用一系列的中間件。

每個中間件可以從App實例,接收三個參數,依次為request對象(代表HTTP請求)、response對象(代表HTTP回應),next回調函數(代表下一個中間件)。每個中間件都可以對HTTP請求(request對象)進行加工,並且決定是否調用next方法,將request對象再傳給下一個中間件。

一個不進行任何操作、只傳遞request對象的中間件,就是下面這樣。

下載並引入koa-router

npm i koa-router --savenconst Koa = require(koa);nconst Router = require(koa-router);nnconst app = new Koa();nconst router = new Router();nnrouter.get(/, async (ctx) => {n let html = `n <ul>n <li><a href="/hello">helloworld</a></li>n <li><a href="/about">about</a></li>n </ul>n `n ctx.body = htmln}).get(/hello, async (ctx) => {n ctx.body = helloworldn}).get(/about, async (ctx) => {n ctx.body = aboutn})nnapp.use(router.routes(), router.allowedMethods())nnapp.listen(3000);n

運行這個 demo,我們將看到與上栗一樣的效果。在這兒我們使用到了第三方中間件。

三、中間件

Koa 的最大特色,也是最重要的一個設計,就是中間件(middleware)Koa 應用程序是一個包含一組中間件函數的對象,它是按照類似堆棧的方式組織和執行的。Koa中使用app.use()用來載入中間件,基本上Koa 所有的功能都是通過中間件實現的。每個中間件默認接受兩個參數,第一個參數是 Context 對象,第二個參數是next函數。只要調用next函數,就可以把執行權轉交給下一個中間件。

下圖為經典的Koa洋蔥模型

我們來運行Koa官網這個小例子:

const Koa = require(koa);nconst app = new Koa();nn// x-response-timennapp.use(async (ctx, next) => {n const start = Date.now();n await next();n const ms = Date.now() - start;n ctx.set(X-Response-Time, `${ms}ms`);n});nn// loggernnapp.use(async (ctx, next) => {n const start = Date.now();n await next();n const ms = Date.now() - start;n console.log(`${ctx.method} ${ctx.url} - ${ms}`);n});nn// responsennapp.use(async ctx => {n ctx.body = Hello World;n});nnapp.listen(3000);n

上面的執行順序就是:請求 ==> x-response-time中間件 ==> logger中間件 ==> 響應中間件 ==> logger中間件 ==> response-time中間件 ==> 響應。 通過這個順序我們可以發現這是個棧結構以"先進後出"(first-in-last-out)的順序執行。Koa已經有了很多好用的中間件*(github.com/koajs/koa/wi)你需要的常用功能基本上都有人實現了*

四、模板引擎

在實際開發中,返回給用戶的網頁往往都寫成模板文件。 Koa 先讀取模板文件,然後將這個模板返回給用戶,這事我們就需要使用模板引擎了,關於Koa的模版引擎,我們只需要安裝koa模板使用中間件koa-views 然後在下載你喜歡的模板引擎*(支持列表)*便可以愉快的使用了。如安裝使用ejs

# 安裝koa模板使用中間件n$ npm i --save koa-viewsnn# 安裝ejs模板引擎n$ npm i --save ejsnconst Koa = require(koa)nconst views = require(koa-views)nconst path = require(path)nconst app = new Koa()nn// 載入模板引擎napp.use(views(path.join(__dirname, ./view), {n extension: ejsn}))nnapp.use(async (ctx) => {n let title = Koa2n await ctx.render(index, {n title,n })n})nnapp.listen(3000)n

./view/index.ejs 模板

<!DOCTYPE html>n<html>n<head>n <title><%= title %></title>n</head>n<body>n <h1><%= title %></h1>n <p>EJS Welcome to <%= title %></p>n</body>n</html>n

打開http://localhost:3000/,你將看到返回了頁面:

關於ejs語法請訪問ejs官網學習:github.com/mde/ejs

五、靜態資源伺服器

網站一般都提供靜態資源(圖片、字體、樣式表、腳本……),我們可以自己實現一個靜態資源伺服器,但這沒必要,koa-static模塊封裝了這部分功能。

$ npm i --save koa-staticnconst Koa = require(koa)nconst path = require(path)nconst static = require(koa-static)nnconst app = new Koa()nn// 靜態資源目錄對於相對入口文件index.js的路徑nconst staticPath = ./staticnnapp.use(static(n path.join(__dirname, staticPath)n))nnnapp.use(async (ctx) => {n ctx.body = hello worldn})nnapp.listen(3000)n

我們訪問localhost:3000/css/app. 將返回app.css 的內容,訪問http://localhost:3000/koa2.png我們將看見返回下圖

六、請求數據的獲取

前文我們主要都在處理數據的響應,這兒我們來了解下Koa獲取請求數據,主要為GETPOST方式。

6.1 GET請求參數的獲取

在koa中,獲取GET請求數據源頭是koa中request對象中的query方法或querystring方法,query返回是格式化好的參數對象,querystring返回的是請求字元串。

  • 請求對象ctx.query*(或ctx.request.query)*,返回如 { a:1, b:2 }
  • 請求字元串 ctx.querystring*(或ctx.request.querystring)*,返回如 a=1&b=2

const Koa = require(koa)nconst app = new Koa()nnapp.use( async ( ctx ) => {n const url = ctx.urln const query = ctx.queryn const querystring = ctx.querystringnn ctx.body = {n url,n query,n querystringn }n})nnapp.listen(3000)n

運行程序並訪問http://localhost:3000/?page=2&limit=10,我們將得到如下結果

{"url":"/?page=2&limit=10","query":{"page":"2","limit":"10"},"querystring":"page=2&limit=10"}n

對了,在這兒推薦個插件:JSONView,用了它你將得到格式化json數據,如下:

{n url: "/?page=2&limit=10",n query: {n page: "2",n limit: "10"n },n querystring: "page=2&limit=10"n}n

更多Koa Request API 請查看koajs.com/#

6.2 POST請求數據獲取

對於POST請求的處理,koa2沒有封裝獲取參數的方法,需要通過自己解析上下文context中的原生node.js請求對象req,將POST表單數據解析成querystring(例如:a=1&b=2&c=3),再將querystring 解析成JSON格式(例如:{"a":"1", "b":"2", "c":"3"}),我們來直接使用koa-bodyparser 模塊從 POST 請求的數據體裡面提取鍵值對。

const Koa = require(koa)nconst app = new Koa()nconst bodyParser = require(koa-bodyparser)nn// 使用koa-bodyparser中間件napp.use(bodyParser())nnapp.use(async (ctx) => {nn if (ctx.url === / && ctx.method === GET) {n // 當GET請求時候返回表單頁面n let html = `n <h1>koa-bodyparser</h1>n <form method="POST" action="/">n Name:<input name="name" /><br/>n Age:<input name="age" /><br/>n Email: <input name="email" /><br/>n <button type="submit">submit</button>n </form>n `n ctx.body = htmln } else if (ctx.url === / && ctx.method === POST) {n // 當POST請求的時候,中間件koa-bodyparser解析POST表單里的數據,並顯示出來n ctx.body = ctx.request.bodyn } else {n // 404n ctx.body = <h1>404 Not Found</h1>n }n})nnapp.listen(3000)n

運行程序,填寫並提交表單,請求結果為:

{n name: "ogilhinn",n age: "120",n email: "[email protected]"n}n

關於更多的Koa知識快打開搜索引擎搜索*([常用的搜索引擎技巧])*繼續學習吧,後續將繼續資料庫的操作以及實現一個簡單的小案例。

參考鏈接

  • Koa官網
  • Koa進階學習筆記
  • Koa 框架教程
  • Koa wiki

二、Node.js使用Nodemailer發送郵件

電子郵件是—種用電子手段提供信息交換的通信方式,是互聯網應用最廣的服務。通過網路的電子郵件系統,用戶可以以非常低廉的價格(不管發送到哪裡,都只需負擔網費)、非常快速的方式(幾秒鐘之內可以發送到世界上任何指定的目的地),與世界上任何一個角落的網路用戶聯繫。

在很多項目中,我們都會遇到郵件註冊,郵件反饋等需求。在node中收發電子郵件也非常簡單,因為強大的社區有各種各樣的包可以供我么直接使用。Nodemailer包就可以幫助我們快速實現發送郵件的功能。

Github源碼:github.com/ogilhinn/nod

Nodemailer簡介

Nodemailer是一個簡單易用的Node.js郵件發送組件

官網地址:https://nodemailer.com

GitHub地址:github.com/nodemailer/n

Nodemailer的主要特點包括:

  • 支持Unicode編碼
  • 支持Window系統環境
  • 支持HTML內容和普通文本內容
  • 支持附件(傳送大附件)
  • 支持HTML內容中嵌入圖片
  • 支持SSL/STARTTLS安全的郵件發送
  • 支持內置的transport方法和其他插件實現的transport方法
  • 支持自定義插件處理消息
  • 支持XOAUTH2登錄驗證

安裝使用

首先,我們肯定是要下載安裝 注意:Node.js v6+

npm install nodemailer --saven

打開官網可以看見一個小例子

use strict;nconst nodemailer = require(nodemailer);nn// Generate test SMTP service account from ethereal.emailn// Only needed if you dont have a real mail account for testingnnodemailer.createTestAccount((err, account) => {nn // create reusable transporter object using the default SMTP transportn let transporter = nodemailer.createTransport({n host: smtp.ethereal.email,n port: 587,n secure: false, // true for 465, false for other portsn auth: {n user: account.user, // generated ethereal usern pass: account.pass // generated ethereal passwordn }n });nn // setup email data with unicode symbolsn let mailOptions = {n from: "Fred Foo ??" <[email protected]>, // sender addressn to: [email protected], [email protected], // list of receiversn subject: Hello ?, // Subject linen text: Hello world?, // plain text bodyn html: <b>Hello world?</b> // html bodyn };nn // send mail with defined transport objectn transporter.sendMail(mailOptions, (error, info) => {n if (error) {n return console.log(error);n }n console.log(Message sent: %s, info.messageId);n // Preview only available when sending through an Ethereal accountn console.log(Preview URL: %s, nodemailer.getTestMessageUrl(info));nn // Message sent: <[email protected]>n // Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...n });n});n

這個小例子是生成了Ethereal的賬戶進行郵件發送演示的。但是這多沒意思,我們來使用自己的郵箱來發送郵件

發出個真實的郵件

這裡我使用了我的qq郵箱給163郵箱發送email。

use strict;nnconst nodemailer = require(nodemailer);nnlet transporter = nodemailer.createTransport({n // host: smtp.ethereal.email,n service: qq, // 使用了內置傳輸發送郵件 查看支持列表:https://nodemailer.com/smtp/well-known/n port: 465, // SMTP 埠n secureConnection: true, // 使用了 SSLn auth: {n user: [email protected],n // 這裡密碼不是qq密碼,是你設置的smtp授權碼n pass: xxxxxx,n }n});nnlet mailOptions = {n from: "JavaScript之禪" <[email protected]>, // sender addressn to: [email protected], // list of receiversn subject: Hello, // Subject linen // 發送text或者html格式n // text: Hello world?, // plain text bodyn html: <b>Hello world?</b> // html bodyn};nn// send mail with defined transport objectntransporter.sendMail(mailOptions, (error, info) => {n if (error) {n return console.log(error);n }n console.log(Message sent: %s, info.messageId);n // Message sent: <[email protected]>n});n

運行程序,成功將返回messageId。這是便可以去收件箱查看這個新郵件啦

這裡我們需要注意,auth.pass 不是郵箱賬戶的密碼而是stmp的授權碼。

到此我們就掌握了發郵件的基本操作。

更多配置

  • CC: Carbon Copy(抄送),用於通知相關的人,收件人可以看到都郵件都抄送給誰了。一般回報工作或跨部門溝通時,都會CC給收件人的領導一份
  • BCC:Blind Carbon Copy(暗抄送),也是用於通知相關的人,但是收件人是看不到郵件被密送給誰了。
  • attachments: 附件

更多配置項:nodemailer.com/message/

這裡我們就不演示CC、BCC了,請自行嘗試。我們來試試發送附件

...n// 只需添加attachments配置項即可nattachments: [n { // utf-8 string as an attachmentn filename: text.txt,n content: hello world!n },n {n filename: ZenQcode.png,n path: path.resolve(__dirname, ZenQcode.png),n }n ]n...n

發送email,就可以收到一個內容為hello world的text.txt文件,以及一個我公眾號的二維碼。

好看的HTML郵件

HTML Email 編寫指南: ruanyifeng.com/blog/201

這兒,我們使用Foundation for Emails: foundation.zurb.com/ema的模板

use strict;nnconst nodemailer = require(nodemailer);nconst ejs = require(ejs);nconst fs = require(fs);nconst path = require(path);nnlet transporter = nodemailer.createTransport({n // host: smtp.ethereal.email,n service: qq, // 使用內置傳輸發送郵件 查看支持列表:https://nodemailer.com/smtp/well-known/n port: 465, // SMTP 埠n secureConnection: true, // 使用 SSLn auth: {n user: [email protected],n // 這裡密碼不是qq密碼,是你設置的smtp授權碼n pass: xxxxxx,n }n});nnlet mailOptions = {n from: "JavaScript之禪" <[email protected]>, // sender addressn to: [email protected], // list of receiversn subject: Hello, // Subject linen // 發送text或者html格式n // text: Hello world?, // plain text bodyn html: fs.createReadStream(path.resolve(__dirname, email.html)) // 流n};nn// send mail with defined transport objectntransporter.sendMail(mailOptions, (error, info) => {n if (error) {n return console.log(error);n }n console.log(Message sent: %s, info.messageId);n // Message sent: <[email protected]>n});n

運行程序,你將如願以償手打如下Email。樣式可能會有細微偏差

上面email中我們用了外鏈的圖片,我們也可以使用附件的方式,將圖片嵌入進去。給附件加個cid屬性即可。

...nlet mailOptions = {n ...n html: <img src="cid:01">, // html bodyn attachments: [n {n filename: ZenQcode.png,n path: path.resolve(__dirname, ZenQcode.png),n cid: 01,n }n ]n};n...n

使用模板引擎

郵件信息一般都不是固定的,我們可以引入模板引擎對HTML內容進行渲染。

這裡我們使用Ejs:github.com/mde/ejs/來做演示

$ npm install ejs --saven

ejs具體語法請參看官方文檔

先建立一個email.ejs文件

<h1>hello <%= title %></h1>n<p><%= desc %></p>n

修改我們的js文件

...nconst template = ejs.compile(fs.readFileSync(path.resolve(__dirname, email.ejs), utf8));nnconst html = template({n title: Ejs,n desc: 使用Ejs渲染模板,n});nnlet mailOptions = {n from: "JavaScript之禪" <[email protected]>, // sender addressn to: [email protected], // list of receiversn subject: Hello, // Subject linen html: html,// html bodyn};n...n

到此,你的郵箱將收到一個動態渲染的hello Ejs。

本文到此告一段落,在此基礎上你可以實現更多有用的功能

HTML email 框架推薦

  • MJML: mjml.io/
  • emailframe emailframe.work/
  • Foundation for Emails 2: https://foundation.zurb.com/emails.html
  • responsive HTML email template: github.com/leemunroe/re
  • campaignmonitor:campaignmonitor.com/a/

推薦閱讀:

Vue 全家桶 + Express 實現的博客(後端API全部自己手寫,很適合剛學習vue以及express的小夥伴學習)
用nvm改變node版本的時候全局模塊找不到
[譯]擴展 Node.js 應用

TAG:Nodejs |