1. Koa 路由
路由(Routing)是由一个URI(或者叫路径)和一个特定的HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应客户端对某个网站节点的访问。
通俗的讲:路由就是根据不同的URL 地址,加载不同的页面实现不同的功能。
1.1 Koa 中我们需要安装koa-router 路由模块来实现路由配置:
- 安装koa-router:
npm install --save koa-router
- 简单的koa-router配置路由的代码:
/*app.js*/
const Koa = require('koa');
const router = require('koa-router')(); //注意:引入的方式
const app = new Koa();
router.get('/', function (ctx, next) {
ctx.body="Hello koa";
})
router.get('/news',(ctx,next)=>{
ctx.body="新闻page"
});
app.use(router.routes()); //作用:启动路由
app.use(router.allowedMethods());
/* 作用: 这是官方文档的推荐用法,我们可以看到router.allowedMethods()用在了路由匹配
router.routes()之后,目的在于:根据ctx.status 设置response 响应头
*/
app.listen(3000,()=>{
console.log('starting at port 3000');
});
1.2 Koa 路由get 传值
在koa2 中GET 传值通过request 接收,但是接收的方法有两种:query
和querystring
。
-
query
:返回的是格式化好的参数对象。 -
querystring
:返回的是请求字符串。 - 获取get请求参数的代码:
/*app.js*/
const Koa = require('koa');
const Router = require('koa-router');
const app = new Koa();
const router = new Router();
router.get('/', (ctx, next) => {
ctx.body="Hello koa";
})
router.get('/newscontent',(ctx,next)=>{
let url =ctx.url;
//从request 中获取GET 请求
let request =ctx.request;
let req_query = request.query;
let req_querystring = request.querystring;
//从上下文中直接获取
let ctx_query = ctx.query;
let ctx_querystring = ctx.querystring;
ctx.body={
url,
req_query,
req_querystring,
ctx_query,
ctx_querystring
}
});
app.use(router.routes()); //作用:启动路由
app.use(router.allowedMethods()); //作用: 当请求出错时的处理逻辑
app.listen(3000,()=>{
console.log('starting at port 3000');
});
1.3 Koa 动态路由
//请求方式http://域名/product/123
router.get('/product/:aid',async (ctx)=>{
console.log(ctx.params); //{ aid: '123' } //获取动态路由的数据
ctx.body='这是商品页面';
});
2. post提交数据的路由配置
2.1 koa-bodyparser获取post提交的数据:
router.post('/uri')
用于配置POST路由,koa-bodyparser
中间件,用来解析POST请求通过表单提交的数据,让我们很方便的获取解析的POST数据,下面是表单页面提交数据和对POST数据解析的示例代码:
/*表单页面,提交地址为/user/login*/
router.get('/user', async (ctx, next)=>{
ctx.body = `
<form action="/user/login" method="post">
<input name="name" type="text" placeholder="请输入用户名:joyitsai">
<br/>
<input name="password" type="password" placeholder="请输入密码:123456">
<br/>
<button>GoGo</button>
</form>
`
});
/**router.post()配置post路由 */
router.post('/user/login', async (ctx, next)=>{
/**ctx.request.body为解析的post数据对象 */
/**{name:'joyitsai', password:'123456'} */
let {name, password} = ctx.request.body;
if(name == 'joyitsai' && password=='123456'){
ctx.body = `Hello ${name}`;
}else{
ctx.body = '账号信息错误'
}
})
访问localhost:3000/user
如下图:
3. Koa项目中的router路由分离:
以上所有的路由配置代码都集中在app.js
文件中,随着项目复杂度增加、业务需求变更,这种做法会给后期的维护工作带来很大的麻烦。我们应该利用MVC
模式思路来优化代码。
3.1 分离Router:
路由部分的代码可以分离成独立的文件,并根据项目结构放在合适的位置和命名,方便管理。在本示例代码中,将上面的登录页面和提交登录数据的代码独立在login.js文件中,结构如下:
|——app.js
|——routes
|——login.js
路由部分的文件代码:
/*login.js*/
const router = require('koa-router')();
module.exports = (app) => {
/**表单页面,提交地址为/user/login */
router.get('/user', async (ctx, next)=>{
ctx.body = `
<form action="/user/login" method="post">
<input name="name" type="text" placeholder="请输入用户名:joyitsai">
<br/>
<input name="password" type="password" placeholder="请输入密码:123456">
<br/>
<button>GoGo</button>
</form>
`
});
/**router.post()配置post路由 */
router.post('/user/login', async (ctx, next)=>{
/**ctx.request.body为解析的post数据对象 */
//{name:'joyitsai', password:'123456'}
console.log(ctx.request.body);
let {name, password} = ctx.request.body;
if(name == 'joyitsai' && password=='123456'){
ctx.body = `Hello ${name}`;
}else{
ctx.body = '账号信息错误'
}
})
app.use(router.routes()).use(router.allowedMethods());
}
路由部分的代码提取成功后,需要在app.js
中引入login.js
:
// 引入Koa
const Koa = require('koa');
const router = require('koa-router')(); /**引入并实例化koa-router */
const bodyParser = require('koa-bodyparser');
const app = new Koa();
app.use(bodyParser());
/*如果有多个路由文件,按照下面同样的方式引入,并应用在app上*/
const loginRouter = require('./routes/login');
loginRouter(app);
app.listen(3000, ()=>{
console.log('cake app running at port 3000')
})
现在项目中只有一个路由文件,并且对HTTP请求的处理函数也很简单,然而随着项目变更,login.js
同样会变得臃肿起来,这时就需要进一步优化分离:
3.2 分离controller
对login.js再次进行优化分离,将对应路由的相应函数提取出来,防止在单独的文件controller/login.js
中,结构如下:
|——app.js
|——routes
| |——login.js
|——controller
|——login.js
controller/login.js,存放响应routes/login.js
中配置的路由的业务逻辑代码:
module.exports = {
user: async (ctx, next) => {
ctx.body = `
<form action="/user/login" method="post">
<input name="name" type="text" placeholder="请输入用户名:joyitsai">
<br/>
<input name="password" type="password" placeholder="请输入密码:123456">
<br/>
<button>GoGo</button>
</form>
`
},
login: async (ctx, next)=>{
/**ctx.request.body为解析的post数据对象 */
console.log(ctx.request.body);
let {name, password} = ctx.request.body;
if(name == 'joyitsai' && password=='123456'){
ctx.body = `Hello ${name}`;
}else{
ctx.body = '账号信息错误'
}
}
}
业务逻辑代码分离之后,需要修改该routes/login.js
文件,在文件中引入controller/login.js
,并以其中的函数作为路由的响应函数,代码如下:
const router = require('koa-router')();
const LoginController = require('../controller/login');
module.exports = (app) => {
/**表单页面,提交地址为/user/login */
router.get('/user', LoginController.user);
/**router.post()配置post路由 */
router.post('/user/login', LoginController.login);
app.use(router.routes()).use(router.allowedMethods());
}
经过上面两次代码分离之后,此时项目结构已经比价清晰了。但实际开发中,Koa需要进行一些数据访问层的操作,如操作数据库、调用第三方接口获取数据
等,这些操作需要分离出Service
层进行处理。相应的,Controller层只需进行业务逻辑部分的处理。
3.3 分离Service:
在service/login.js
中,用于抽离controller/login.js
中的数据访问相关的代码,结构如下:
|——app.js
|——routes
| |——login.js
|——controller
| |——login.js
|——service
|——login.js
service/login.js代码如下:
module.exports = {
getUserdata: async (username)=>{
/**这里结合数据库操作,通过username获取数据库中的用户数据,省略相关代码*/
let userdata = {username: 'joyitsai', password:'123456'}
/**查询到了userdata,返回 */
return userdata;
}
}
在controller/login.js中引入service/login.js:
const LoginService = require('../service/login');
module.exports = {
// .....省略表单页面代码
login: async (ctx, next)=>{
/**ctx.request.body为解析的post数据对象 */
let {name, password} = ctx.request.body;
/*通过name去数据库查询用户数据*/
let userdata = LoginService.getUserdata(name);
if(name == userdata.username && password == userdata.password){
ctx.body = `Hello ${name}`;
}else{
ctx.body = '账号信息错误'
}
}
}