路由将 URL 解析到对应的处理程序。这里我们将使用 Koa 的中间件 koa-router 来处理请求,将请求解析到对应的控制器(controller)上,实现访问不同地址获得不同的结果。不过在此之前,我们先了解使用原生koa实现路由的方式。
Koa原生路由实现
查看路由信息
首先,通过 ctx.request.url
获取到当前请求的地址:
// app.js
const Koa = require('koa');
const app = new Koa();
// 响应
app.use(ctx => {
const {url} = ctx.request;
ctx.response.body = url;
});
app.listen(3000);
启动服务之后我们在浏览器访问 http://localhost:3000 的任何一个地址,可在页面中看到返回的 url 信息。
了解内容协商
Koa使用 accepts 作为内容协商(content negotiation),accept
能告诉服务器浏览器接受什么样的数据类型,默认的返回类型是 text/plain
,若要返回其他类型的内容则用 ctx.request.accepts
在请求头部附带信息,然后用 ctx.response.type
指定返回类型,示例:
const main = ctx => {
if (ctx.request.accepts('xml')) {
ctx.response.type = 'xml';
ctx.response.body = '<data>Hello World</data>';
} else if (ctx.request.accepts('json')) {
ctx.response.type = 'json';
ctx.response.body = { data: 'Hello World' };
} else if (ctx.request.accepts('html')) {
ctx.response.type = 'html';
ctx.response.body = '<p>Hello World</p>';
} else {
ctx.response.type = 'text';
ctx.response.body = 'Hello World';
}
};
可以使用 acceptsEncodings
设置接收返回的编码,acceptsCharsets
设置接收返回的字符集,acceptsLanguages
设置接收返回的语言。
通过路由控制页面访问
接下来我们通过对路由地址进行判断,并取到对应的HTML页面返回到浏览器显示。
首先,新建 HTML 文件如下:
<!--app/view/index.html-->
<h1>Index Page</h1>
<a href="home">home</a>
<!--app/view/home.html-->
<h1>Home Page</h1>
<a href="index">index</a>
<!--app/view/404.html-->
<h1>404 访问的页面不存在</h1>
<a href="home">home</a>
接着,我们需要读取 HTML 文件,约定 HTML 都在 app/view/
目录,然后从这个目录读取页面,并且返回到浏览器显示:
// app.js
const Koa = require('koa');
const app = new Koa();
const fs = require('fs'); // 引入fs
/**
* 从app/view目录读取HTML文件
* @param {string} page 路由指向的页面
* @returns {Promise<any>}
*/
function readPage( page ) {
return new Promise(( resolve, reject ) => {
const viewUrl = `./app/view/${page}`;
fs.readFile(viewUrl, "binary", ( err, data ) => {
if ( err ) {
reject( err )
} else {
resolve( data )
}
})
})
}
// 路由
app.use(async ctx => {
const {url} = ctx.request;
let page;
switch ( url ) {
case '/':
page = 'index.html';
break;
case '/index':
page = 'index.html';
break;
case '/home':
page = 'home.html';
break;
default:
page = '404.html';
break
}
ctx.response.type = 'html'; // 这里设置返回的类型是html
ctx.response.body = await readPage(page);
});
app.listen(3000, () => {
console.log('App started on http://localhost:3000')
});
然后我们启动服务,在浏览器访问 http://localhost:3000/index ,我们可以看到页面已经显示出来,点击里面的连接,就能够切换不同的页面。
使用koa-router
从上面的实战可以看到,要针对不同的访问返回不同的内容,我们需要先获取请求的 url,以及请求的类型,再进行相应的处理,最后返回结果,考虑到使用原生路由处理请求会很繁琐,我们使用 koa-router 中间件来管理项目路由。
安装和使用
执行命令安装 koa-router:
$ npm install koa-router --save
接着修改之前的路由代码,使用 koa-router
:
// app.js
const Koa = require('koa');
const app = new Koa();
const fs = require('fs'); // 引入fs
// 引入koa-router
const Router = require('koa-router');
const router = new Router();
/**
* 从app/view目录读取HTML文件
* @param {string} page 路由指向的页面
* @returns {Promise<any>}
*/
function readPage( page ) {
return new Promise(( resolve, reject ) => {
const viewUrl = `./app/view/${page}`;
fs.readFile(viewUrl, "binary", ( err, data ) => {
if ( err ) {
reject( err )
} else {
resolve( data )
}
})
})
}
// 原生路由
// app.use(async ctx => {
// const {url} = ctx.request;
// let page;
// switch ( url ) {
// case '/':
// page = 'index.html';
// break;
// case '/index':
// page = 'index.html';
// break;
// case '/home':
// page = 'home.html';
// break;
// default:
// page = '404.html';
// break
// }
// ctx.response.type = 'html'; // 这里设置返回的类型是html
// ctx.response.body = await readPage(page);
// });
// koa-router
const index = async (ctx, next) => {
ctx.response.type = 'html';
ctx.response.body = await readPage('./index.html');
};
const home = async (ctx, next) => {
ctx.response.type = 'html';
ctx.response.body = await readPage('./home.html');
};
router.get('/', index);
router.get('/index', index);
router.get('/home', home);
// 使用中间件 处理404
router.use(async (ctx, next) => {
await next(); // 调用next执行下一个中间件
if(ctx.status === 404) {
ctx.response.type = 'html';
ctx.response.body = await readPage('./404.html');
}
});
// 使用koa-router中间件
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log('App started on http://localhost:3000')
});
在以上代码中,我们使用 ctx.response.type
来设置响应的类型,响应内容为 HTML 标签,并且通过添加路由中间件,执行 npm start
启动服务即可预览。
单独管理路由
考虑到以后项目会复杂很多,我们把路由独立出来,新增文件管理路由:
// app/router/index.js
const fs = require('fs'); // 引入fs
const Router = require('koa-router');
const router = new Router();
/**
* 从app/view目录读取HTML文件
* @param {string} page 路由指向的页面
* @returns {Promise<any>}
*/
function readPage( page ) {
return new Promise(( resolve, reject ) => {
const viewUrl = `./app/view/${page}`;
fs.readFile(viewUrl, "binary", ( err, data ) => {
if ( err ) {
reject( err )
} else {
resolve( data )
}
})
})
}
// koa-router
const index = async (ctx, next) => {
ctx.response.type = 'html';
ctx.response.body = await readPage('./index.html');
};
const home = async (ctx, next) => {
ctx.response.type = 'html';
ctx.response.body = await readPage('./home.html');
};
router.get('/', index);
router.get('/index', index);
router.get('/home', home);
module.exports = router;
// app.js
const Koa = require('koa');
const app = new Koa();
// 引入路由文件
const router = require('./app/router');
// 使用中间件 处理404
app.use(async (ctx, next) => {
await next(); // 调用next执行下一个中间件
if(ctx.status === 404) {
ctx.response.type = 'html';
ctx.response.body = '404'; // 移除了读取页面的方法
}
});
// 使用koa-router中间件
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log('App started on http://localhost:3000')
});
重新启动服务,访问 http://localhost:3000/ 看看是否生效。
使用模板引擎
为了便于读取模板和渲染页面,我们将使用中间件 koa-nunjucks-2 来作为模板引擎。
首先安装 koa-nunjucks-2 :
$ npm i koa-nunjucks-2 --save
在使用路由之前应用 koa-nunjucks-2:
// app.js
const Koa = require('koa');
const app = new Koa();
// 引入模板引擎
const koaNunjucks = require('koa-nunjucks-2');
const path = require('path');
// 引入路由文件
const router = require('./app/router');
// 使用模板引擎
app.use(koaNunjucks({
ext: 'html',
path: path.join(__dirname, 'app/view'),
nunjucksConfig: {
trimBlocks: true // 开启转义 防止Xss
}
}));
// 使用中间件 处理404
app.use(async (ctx, next) => {
await next(); // 调用next执行下一个中间件
if(ctx.status === 404) {
await ctx.render('404');
}
});
// 使用koa-router中间件
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log('App started on http://localhost:3000')
});
// app/router/index.js
const Router = require('koa-router');
const router = new Router();
// koa-router
const index = async (ctx, next) => {
await ctx.render('index', {title: 'Index', link: 'home'});
};
const home = async (ctx, next) => {
await ctx.render('index', {title: 'Home', link: 'index'});
};
router.get('/', index);
router.get('/index', index);
router.get('/home', home);
module.exports = router;
分模块管理路由
为了细化路由,我们将根据业务分开管理路由:
// app/router/home.js
const router = require('koa-router')();
router.get('/', async (ctx, next) => {
await ctx.render('index', {title: 'Home', link: 'index'});
});
module.exports = router;
// app/router/index.js
const Router = require('koa-router');
const router = new Router();
const home = require('./home');
const index = async (ctx, next) => {
await ctx.render('index', {title: 'Index', link: 'home'});
};
router.get('/', index);
router.get('/index', index);
router.use('/home', home.routes(), home.allowedMethods()); // 设置home的路由
module.exports = router;
我们将首页相关的业务放到了 app/router/home.js
文件中进行管理,并且在 app/router/index.js
中引入了,为 home
分配了一个路径 /home
,以后就通过这个路由增加首页相关的功能,重启服务,访问 http://localhost:3000/home 即可看到配置的路由。
为路由增加前缀
// config.js
const CONFIG = {
"API_PREFIX": "/api" // 配置了路由前缀
};
module.exports = CONFIG;
// app/router/index.js
const config = require('../../config/config');
const Router = require('koa-router');
const router = new Router();
router.prefix(config.API_PREFIX); // 设置路由前缀
const home = require('./home');
const index = async (ctx, next) => {
await ctx.render('index', {title: 'Index', link: 'home'});
};
router.get('/', index);
router.get('/index', index);
router.use('/home', home.routes(), home.allowedMethods()); // 设置home的路由
module.exports = router;
// app.js
const Koa = require('koa');
const app = new Koa();
//...
app.listen(3000, () => {
console.log('App started on http://localhost:3000/api')
});
重新启动服务,访问 http://localhost:3000/api 和 http://localhost:3000/api/home 即可看到新配置的路由。
删除没有用到的文件 app/view/home.html
之后,整个文件目录如下:
koa-blog
├── package.json
├── app.js
├── app
│ ├── router
│ | ├── homde.js
│ | └── index.js
│ └── view
│ ├── 404.html
│ └── index.html
└── config
└── config.js
网友评论