利用node直接實現服務器是運用http模塊,Express和Koa都是在其上作的封裝,
這篇wiki只是想直觀的看看封裝先後基本使用上的不一樣,先不去考慮深刻的東西。html
var http = require("http"); http.createServer(function(req, res) { // 主頁 if (req.url == "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.write("Welcome to the homepage!"); res.end("Welcome to the homepage!"); } // About頁面 else if (req.url == "/about") { res.writeHead(200, { "Content-Type": "text/html" }); res.end("Welcome to the about page!"); } // 404錯誤 else { res.writeHead(404, { "Content-Type": "text/plain" }); res.end("404 error! File not found."); } }).listen(8080, "localhost");
http模塊的createServer直接就能建立一個服務器的實例,而後調用實例的listen方法,傳入監聽的端口與主機就ok了,node
處理函數把http的request和response對象做爲兩個參數進行操做。express
實現路由: 經過請求的url來判斷json
寫響應頭部:res.writeHead方法api
寫響應body: res.write數組
結束響應: res.end緩存
var http = require('http'); http.createServer(function (req, res) { var content = ""; req.on('data', function (chunk) { content += chunk; }); req.on('end', function () { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("You've sent: " + content); res.end(); }); }).listen(8080);
監聽req的data和end事件,data事件會在數據接收過程當中,每收到一段數據就觸發一次,
接收到的數據被傳入回調函數。end事件則是在全部數據接收完成後觸發。服務器
簡單說,中間件(middleware)就是處理HTTP請求的函數。它最大的特色就是,一箇中間件處理完,再傳遞給下一個中間件。app
App實例在運行過程當中,會調用一系列的中間件。每一箇中間件能夠從App實例,接收三個參數,
依次爲request對象(表明HTTP請求)、response對象(表明HTTP迴應),next回調函數(表明下一個中間件)。框架
每一箇中間件均可以對HTTP請求(request對象)進行加工,而且決定是否調用next方法,將request對象再傳給下一個中間件。
一個不進行任何操做、只傳遞request對象的中間件,就是下面這樣。
function uselessMiddleware(req, res, next) { next(); }
上面代碼的next就是下一個中間件。若是它帶有參數,則表明拋出一個錯誤,參數爲錯誤文本。
function uselessMiddleware(req, res, next) { next('出錯了!'); }
拋出錯誤之後,後面的中間件將再也不執行,直到發現一個錯誤處理函數爲止。
use是express註冊中間件的方法。
app.use(function(request, response, next) { console.log("In comes a " + request.method + " to " + request.url); next(); }); app.use(function(request, response) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Hello world!\n"); });
能夠利用request.url屬性,判斷請求的網址,從而返回不一樣的內容,實現路由。
app.use(function(request, response, next) { if (request.url == "/") { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Welcome to the homepage!\n"); } else { next(); } }); app.use(function(request, response, next) { if (request.url == "/about") { response.writeHead(200, { "Content-Type": "text/plain" }); } else { next(); } });
除了在回調函數內部判斷請求的網址,use方法也容許將請求網址寫在第一個參數。
這表明,只有請求路徑匹配這個參數,後面的中間件纔會生效。無疑,這樣寫更加清晰和方便。
app.use("/home", function(request, response, next) { response.writeHead(200, { "Content-Type": "text/plain" }); response.end("Welcome to the homepage!\n"); });
針對不一樣的請求,use能夠有不一樣的別名,分別對應http的方法,包括get post put post delete。
var router = express.Router(); router.get('/', function(req, res) { res.send('首頁'); }); router.get('/about', function(req, res) { res.send('關於'); }); app.use('/', router);
router可以自由掛載和直接把路由寫在use上相比,可以爲程序書寫帶來更大的靈活性。
爲何要單獨說這個post請求,由於獲取request的body不是可以經過request的一個body屬性就能夠的,
經過http處理post的請求中咱們能夠看到,須要經過監聽request的data和end方法進行拼接,由於body可能分屢次傳過來。
利用框架的好處就是有人寫了中間件,能夠直接用。Express中處理body的中間件用body-parser
var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));
body-parser提供了一下幾種轉換格式
JSON body parser
Raw body parser
Text body parser
URL-encoded form body parser
利用中間件之後,能夠直接利用request.body直接獲取轉換後的body。
router.post('/testpost', function(req, res, next) { console.log('testpost'); res.send(req.body); });
一個Koa應用就是一個對象,包含了一個middleware數組,這個數組由一組Generator函數組成。
這些函數負責對HTTP請求進行各類加工,好比生成緩存、指定代理、請求重定向等等。
var koa = require('koa'); var app = koa(); app.use(function *(){ this.body = 'Hello World'; }); app.listen(3000);
能夠看到,Koa框架和Express框架使用起來很類似。那麼重點說的應該是Koa框架的不一樣之處:
1.中間件用Generator函數,因此中間件利用了Generator函數的中斷等待特性
2.把request和response對象封裝到了context中,經過this訪問,因此操做的api會有不一樣。
Koa中間件與Express的不一樣就在於它是Generator函數,Generator函數內部使用yield命令,將程序的執行權轉交給下一個中間件,
即yield next,要等到下一個中間件返回結果,纔會繼續往下執行,因此是嵌套執行的順序。
app.use(function *(next){ console.log('>> one'); yield next; console.log('<< one'); }); app.use(function *(next){ console.log('>> two'); this.body = 'two'; console.log('<< two'); });
輸出:
>> one >> two << one << two
因此當須要有異步操做的時候,咱們能夠用yield,將控制權交給它,沒必要將處理邏輯寫在回調函數中。
Generator函數會返回一個遍歷器對象,yield語句就是暫停的標識,Koa框架則會自動的遍歷Generator函數,直到結束,返回http請求。
因此在什麼時候返回http請求,koa沒有像http模塊和Express框架那樣顯示的指定,好比調用res.end,res.send等方法來結束http響應。
koa則是在執行完全部中間件之後自動的返回http請求。不會等待未完成的異步操做
兩種方式
一種是用this.path作判斷
let koa = require('koa') let app = koa() // normal route app.use(function* (next) { if (this.path !== '/') { return yield next } this.body = 'hello world' });
一種是用koa-router插件,相似於Express的use和一系列http動詞方法。
var app = require('koa')(); var Router = require('koa-router'); var myRouter = new Router(); myRouter.get('/', function *(next) { this.response.body = 'Hello World!'; }); app.use(myRouter.routes()); app.listen(3000);
中間件當中的this表示上下文對象context,表明一次HTTP請求和迴應,即一次訪問/迴應的全部信息,均可以從上下文對象得到。
context對象封裝了request和response對象,而且提供了一些輔助方法。每次HTTP請求,就會建立一個新的context對象。
context對象的全局屬性。
request:指向Request對象
response:指向Response對象
req:指向Node的request對象
req:指向Node的response對象
app:指向App對象
state:用於在中間件傳遞信息。
其實就是如何獲取reauest中的body,利用中間件co-body,處理後能夠經過this.request.body訪問
// application/json var body = yield parse.json(this); // application/x-www-form-urlencoded var body = yield parse.form(this); // text/plain var body = yield parse.text(this);