用Node.js開發Web服務器端,有幾個顯著的優點:
速度快,很是快!這得益於Node.js天生是異步的。
好消息是這個教程已經幫你選好了,你只須要跟着教程一條道走到黑就能夠了。
koa是Express的下一代基於Node.js的web框架,目前有1.x和2.0兩個版本。建議用2.0
Express是第一代最流行的web框架,它對Node.js的http進行了封裝
var
express =
require
(
'express'
);
var
app = express(); app.get(
'/'
,
function
(req, res) { res.send(
'Hello World!'
); }); app.listen(
3000
,
function
() { console.log(
'Example app listening on port 3000!'
); });
koa2的代碼看上去像這樣:
app.
use
(async (ctx, next) => { await next();
var
data = await doReadFile(); ctx.response.type =
'text/plain'
; ctx.response.body = data; });
koa入門
如何安裝koa2
能夠用npm命令直接安裝koa。先打開命令提示符,務必把當前目錄切換到
文件所在的那個
目錄,而後執行命令:
npm install koa
@2
.
0
.
0
任什麼時候候均可以直接刪除整個
node_modules
目錄,由於用
npm install
命令能夠完整地從新下載全部依賴。而且,這個目錄不該該被放入版本控制中。
或者經過下面方式安裝:
建立一個
package.json
,這個文件描述了咱們的
hello-koa
工程會用到哪些包
{ "
name
":
"hello-koa2"
, "
version
":
"1.0.0"
, "
description
":
"Hello Koa 2 example with async"
, "
main
":
"app.js"
, "
scripts
": { "
start
":
"node app.js"
}, "
keywords
": [
"koa"
,
"async"
], "
author
":
"Michael Liao"
, "
license
":
"Apache-2.0"
, "
repository
": { "
type
":
"git"
, "
url
":
"https://github.com/michaelliao/learn-javascript.git"
}, "
dependencies
": { "
koa
":
"2.0.0"
} }
其中,
dependencies
描述了咱們的工程依賴的包以及版本號。其餘字段均用來描述項目信息,
可任意填寫。
而後,咱們在
hello-koa
目錄下執行
npm install
就能夠把所需包以及依賴包一次性所有裝好:
npm start
命令會讓npm執行定義在
package.json
文件中的start對應命令
// 導入koa,和koa 1.x不一樣,在koa2中,咱們導入的是一個class,所以用大寫的Koa表示:
const
Koa =
require
(
'koa'
);
// 建立一個Koa對象表示web app自己:
const
app =
new
Koa();
// 對於任何請求,app將調用該
異步函數
處理請求:
app.
use
(async (ctx, next) => { await next(); ctx.response.type =
'text/html'
; ctx.response.body =
'<h1>Hello, koa2!</h1>'
; });
// 在端口3000監聽:
app.listen(
3000
); console.log(
'app started at port 3000...'
);
其中,參數
ctx
是由koa傳入的
封裝了request和response的變量
,咱們能夠經過它訪問request和response,
next
是koa傳入的將要處理的下一個異步函數。
async
標記的函數稱爲異步函數,在異步函數中,能夠用
await
調用另外一個異步函數,這兩個關鍵字將在ES7中引入。
每收到一個http請求,koa就會調用經過
app.use()
註冊的async函數,並傳入
ctx
和
next
參數。
爲何要調用
await next()
?
緣由是koa把不少async函數組成一個處理鏈,每一個async函數均可以作一些本身的事情,而後用
await next()
來調用下一個async函數。咱們把每一個async函數稱爲middleware,這些middleware能夠組合起來,完成不少有用的功能。
console.log(`${ctx.request.method} ${ctx.request.url}`);
// 打印URL
const
ms =
new
Date().getTime() - start;
// 耗費時間
console.log(`Time: ${ms}ms`);
// 打印耗費時間
若是一個middleware沒有調用
await next()
,會怎麼辦?答案是後續的middleware將再也不執行了。
例如,一個檢測用戶權限的middleware能夠決定是否繼續處理請求,仍是直接返回403錯誤:
app.use(async (ctx,
next
) => {
if
(await checkUserPermission(ctx)) { await
next
(); }
else
{ ctx.response.status =
403
; } });
處理url路由
"koa-router": "7.0.0"
const
Koa = require(
'koa'
);
// 注意require('koa-router')返回的是函數:
const
router = require(
'koa-router'
)();
const
app =
new
Koa();
// log request URL:
app.use(async (ctx, next) => { console.log(`Process ${ctx.request.method} ${ctx.request.url}...`); await next(); });
// add url-route:
router.get(
'/hello/:name'
, async (ctx, next) => {
var
name =
ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!
</h1>
`; });
router.get
('/', async (ctx, next) => { ctx.response.body = '
<h1>
Index
</h1>
'; }); // add router middleware: app.use(router.routes()); app.listen(3000); console.log('app started at port 3000...');
注意導入
koa-router
的語句最後的
()
是函數調用:
處理post請求
能夠用
router.post('/path', async ...
注意:
須要引入另外一個middleware來解析原始request請求,而後,把解析後的參數,綁定到
ctx.request.body
中。
"koa-bodyparser": "3.2.0"
const
bodyParser =
require
(
'koa-bodyparser'
);
在合適的位置加上:
app.
use
(bodyParser());
因爲middleware的順序很重要,這個
koa-bodyparser
必須在
router
以前被註冊到
app
對象上。
name = ctx.request.body.name || '', //
默認值
把URL處理函數集中到某幾個js文件中
好比 在
controllers
目錄下編寫
index.js
:
var fn_index = async (ctx, next) => { ctx.response.body = `
<h1>
Index
</h1>
<form
action
=
"/signin"
method
=
"post"
>
<p>
Name:
<input
name
=
"name"
value
=
"koa"
></p>
<p>
Password:
<input
name
=
"password"
type
=
"password"
></p>
<p><input
type
=
"submit"
value
=
"Submit"
></p>
</form>
`; };
...
module.exports = { 'GET /': fn_index, 'POST /signin': fn_signin };
另外一個
var
fn_hello = async (ctx, next) => {
var
name = ctx.params.name; ctx.response.body = `<h1>Hello, ${name}!
</h1>
`; }; module.exports = { 'GET /hello/:name': fn_hello };
修改
app.js
,讓它自動掃描
controllers
目錄,找到全部
js
文件,導入,而後註冊每一個URL:
let
命令,用來聲明變量。它的用法相似於
var
,可是所聲明的變量,只在
let
命令所在的代碼塊內有效。
for
循環的計數器,就很合適使用
let
命令。
const
fs =
require
(
'fs'
);
function
addMapping
(router, mapping) {
for
(
var
url
in
mapping) {
if
(url.startsWith(
'GET '
)) {
var
path = url.substring(
4
); router.get(path, mapping[url]); console.log(`register URL mapping: GET ${path}`); }
else
if
(url.startsWith(
'POST '
)) {
var
path = url.substring(
5
); router.post(path, mapping[url]); console.log(`register URL mapping: POST ${path}`); }
else
{ console.log(`invalid URL: ${url}`); } } }
function
addControllers
(router) {
var
files = fs.readdirSync(__dirname +
'/controllers'
);
var
js_files = files.filter((f) => {
return
f.endsWith(
'.js'
); });
for
(
var
f of js_files) { console.log(`process controller: ${f}...`);
let
mapping = require(__dirname +
'/controllers/'
+ f); addMapping(router, mapping); } } //addControllers(router);
module.exports =
function
(dir) { let controllers_dir = dir ||
'controllers'
,
// 若是不傳參數,掃描目錄默認爲'controllers'
router =
require
(
'koa-router'
)(); addControllers(router,
controllers_dir
);
return
router.routes(); };
主文件中
// 導入controller middleware:
const
controller =
require
(
'./controller'
); ...
// 使用middleware:
app.
use
(controller());
其它:
Nunjucks
模板引擎