利用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);