浅谈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);
相关文章
相关标签/搜索