淺談Http模塊,Express和Koa實現http服務

前言

利用node直接實現服務器是運用http模塊,Express和Koa都是在其上作的封裝,
這篇wiki只是想直觀的看看封裝先後基本使用上的不一樣,先不去考慮深刻的東西。html

1、http模塊

1.1 處理get請求

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緩存

1.2 處理Post請求

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事件則是在全部數據接收完成後觸發。服務器

2、Express框架

2.1 中間件

簡單說,中間件(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");
});

2.2 路由的實現

2.2.1 request.url

能夠利用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();
  }
});

2.2.2 use等方法

除了在回調函數內部判斷請求的網址,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。

2.2.3 利用Express.Router

var router = express.Router();
 
router.get('/', function(req, res) {
  res.send('首頁');
});
 
router.get('/about', function(req, res) {
  res.send('關於');
});
 
app.use('/', router);

router可以自由掛載和直接把路由寫在use上相比,可以爲程序書寫帶來更大的靈活性。

2.3 處理POST請求

爲何要單獨說這個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);
});

3、Koa框架

一個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會有不一樣。

3.1 中間件

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請求。不會等待未完成的異步操做

3.2路由

兩種方式

一種是用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);

3.3 context對象

中間件當中的this表示上下文對象context,表明一次HTTP請求和迴應,即一次訪問/迴應的全部信息,均可以從上下文對象得到。

context對象封裝了request和response對象,而且提供了一些輔助方法。每次HTTP請求,就會建立一個新的context對象。

context對象的全局屬性。

  • request:指向Request對象

  • response:指向Response對象

  • req:指向Node的request對象

  • req:指向Node的response對象

  • app:指向App對象

  • state:用於在中間件傳遞信息。

3.4 處理Post的請求

其實就是如何獲取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);
相關文章
相關標籤/搜索