Koa
基于NodeJs的web应用框架,由Express的原班人马打造,致力于提供一个轻量级的框架,几乎所有功能都需要第三方的中间件来辅助完成,使用了node的新特性,比express更简洁,更轻量
express与koa对比
koa相对于express更加年轻,意味着express生态更加成熟,koa比express更加轻量,本身只提供一个架子,几乎所有功能都需要依赖于第三方插件,而express自身就集成了许多功能,这也意味着express更加笨重,express对于初学者更加友好,自身的功能足够使用,而koa则学习成本更高,毕竟连核心的路由也去掉了,都需要通过学习第三方中间件来实现,而很多中间件的功能一样,api却不同,koa使用了很多node的新特性及es6的新特性,而express则语法上比较陈旧一点,但是兼容性更好
koa起步
生成项目文件并初始化包管理文件package.json
mkdir myapp && cd myapp && npm init -y
下载koa模块
npm install koa -S
创建app.js
touch app.js
编辑app.js
// 引入koa模块
const Koa = require('koa');
// 实例化koa
const app = new Koa();
// 创建接受Context对象的函数,Context由koa提供,表示一次对话的上下文
const main = ctx => {
// ctx包含请求及响应对象,通过响应对象的body设置返回的内容
ctx.response.body = 'Hello World';
}
// 使用加载main函数,注册到koa
app.use(main);
// 监听并启动服务
app.listen(3000);
衔接上文对象,ctx.response.type设置返回数据类型
const Koa = require('koa');
const app = new Koa();
const main = ctx => {
// text或text/plain纯文本
// html或text/html解析为html
// json
ctx.response.type = 'html';
ctx.response.body = 'Hello World';
}
app.use(main);
app.listen(3000);
路由
简单来说路由间url到函数的映射,一个url指向一个地址,由此执行一个对应的规则,通常在web中理解为一个函数,而url到这个函数的过程称之为路由
原生路由
网站一般都是由多个页面组成的,不同的url指向不同的页面,在koa中可以通过ctx.request.path获取用户请求的路径
我们可以将我们的body指向一个网页模板,通过fs.createReadStream()获取文件流
const Koa = require('koa');
const fs = require('fs');
const app = new Koa();
const main = ctx => {
ctx.response.type = 'html';
if(ctx.request.path === '/') {
ctx.response.body = fs.createReadStream('./index.html');
}
else {
ctx.response.body = '页面未找到';
}
}
app.use(main);
app.listen(3000);
中间件
简单来说就是处于操作系统和应用软件之间的一个类或者说插件,具有承上启下的作用,用于连接两个模块,可重用的与业务逻辑无关的各种组件
koa-route模块
koa-route是koa的一个第三方中间件,当然还有koa-router,文章里的相对简单一点
const Koa = require('koa');
const app = new Koa();
const fs = require('fs');
const route = require('koa-route');
const about = require('./about.js');
const home = require('./home.js');
app.use(route.get('/home', home));
app.use(route.get('/about', about));
app.listen(3000);
home.js
const home = cxt => {
console.log(cxt)
cxt.response.body = '首页';
}
module.exports = home;
about.js
const about = cxt => {
cxt.response.body = '关于我们';
}
module.exports = about;
静态资源
网站的静态资源(脚本、图片、字体、样式表),假如为他们都写一个路由将会很麻烦,比如用户需要单独访问该服务地址下的一张图片就很不方便,static就类似一个web容器
这里用到了koa-static
const Koa = require('koa');
const app = new Koa();
const path = require('path');
const static = require('koa-static');
const main = static(path.join(__dirname, 'static'));
app.use(main);
app.listen(3000);
重定向
重新指定方向(路由),有时候当用户访问一个页面,当用户权限不够或者其他问题的时候,我们需要给用户一个响应,则需要重新为用户指定页面
const Koa = require('koa');
const app = new Koa();
const route = require('koa-route');
const redirect = ctx => {
ctx.response.redirect('/');
};
const main = ctx => {
ctx.response.body = '首页';
};
app.use(route.get('/redirect', redirect));
app.use(route.get('/', main));
app.listen(3000);
异步中间件
当出现异步操作时,比如异步读取文件,查询数据库等,我们就必须把我们的中间件设置为异步
const Koa = require('koa');
const app = new Koa();
const route = require('koa-route');
const fs = require('fs');
function readFile() {
return new Promise((resolve, reject) => {
fs.readFile('./index.html', (err, data) => {
resolve(data);
})
})
}
const main = async function (ctx, next) {
ctx.response.type = 'html';
ctx.response.body = await readFile();
};
app.use(main);
app.listen(2000);
中间件的合成
koa-compose模块可以将多个中间件合成为一个
const compose = require('koa-compose');
const logger = (ctx, next) => {
console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);
next();
}
const main = ctx => {
ctx.response.body = 'Hello World';
};
const middlewares = compose([logger, main]);
app.use(middlewares);
错误处理
如果代码运行过程中发生错误,我们需要把错误信息返回给用户。HTTP 协定约定这时要返回500状态码。
ctx.throw()
const Koa = require('koa');
const app = new Koa();
const main = async function (ctx, next) {
ctx.throw(500)
};
app.use(main);
app.listen(2000);
404错误
const main = ctx => {
ctx.response.status = 404;// 等同于ctx.throw(404)
ctx.response.body = 'Page Not Found';
};
错误处理中间件
const handler = async (ctx, next) => {
try {
await next();
}
catch (err) {
ctx.response.status = err.statusCode || err.status || 500;
ctx.response.body = {
message: err.message
};
}
};
const main = ctx => {
ctx.throw(500);
};
app.use(handler);
app.use(main);
文章中多次用到next,简单理解就是当我们同时使用两个中间件的时候,会发现先use的会执行,而后面的中间件则不会执行,这时候我们需要使用next把我们中间件的执行权交给下一个中间件
async和await需要配合使用,await会给其后的表达式包裹一个promise进行返回
以上参考阮一峰大大的文章!!!