处理路由
摘要
Koa
怎么处理 url
# 简单处理
const Koa = require("koa");
const app = new Koa();
app.use(async (ctx, next) => {
ctx.type = "text/html";
if (ctx.request.path == "/") {
ctx.body = "<h2>hello world!</h2>";
} else {
await next();
}
});
app.use(async (ctx, next) => {
if (ctx.request.path == "/error") {
ctx.response.body = "<p style='color:red;'>Error!</p>";
} else {
await next();
}
});
app.use(async (ctx, next) => {
if (ctx.request.path == "/login") {
ctx.response.body = "<p style='color:blue;'>login!</p>";
} else {
await next();
}
});
app.listen(3000, () => {
console.log("http://localhost:3000");
});
尽管可以这么写,但是太麻烦了,所以引入一个模块 koa-router
,Koa 称之为中间件,koa-router
这个中间件可以集中处理 URL,根据不同的 URL 调用不同的处理函数
# 使用 koa-router
cnpm install koa-router -S
const Koa = require("koa");
// 注意require('koa-router')返回的是函数:
const Router = require("koa-router");
const router = new Router();
const app = new Koa();
app.use(async (ctx, next) => {
ctx.type = "text/html";
ctx.body = `${ ctx.request.url }`;
await next();
});
router.get('/hello/:name', async (ctx, next) => {
var name = ctx.params.name;
ctx.body = `<h2>hello ${ name } </h2>`;
});
// 注册使用 koa-router
app.use(router.routes());
app.listen(3000, () => {
console.log("http://localhost:3000");
});
类似的,put、delete、head请求也可以由router处理。
用post请求处理URL时,我们会遇到一个问题:
post请求通常会发送一个表单,或者JSON,它作为request的body发送,但无论是Node.js提供的原始request对象,还是koa提供的request对象,都不提供解析request的body的功能!
这个时候需要用到 koa 的另外一个中间件 koa-bodyparser
用来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body
中。
查询资料后发现,如果是要做图片上传,还需要使用 koa-multer
这个中间件。
所以,最后决定使用 koa-body
来代替这两个中间件
# 使用 koa-body
cnpm install koa-body -S
const Koa = require("koa");
const koaBody = require("koa-body");
const Router = require("koa-router");
const router = new Router();
const app = new Koa();
router.get('/', async (ctx, next) => {
ctx.type = "text/html";
ctx.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
});
router.post('/signin', async (ctx, next) => {
var body = ctx.request.body;
var name = body.name || '';
var pwd = body.password || '';
console.log(`name: ${name} && pwd: ${pwd}`);
if (name == "koa" && pwd == "demo") {
ctx.body = "<h1>Success Login</h1>";
} else {
ctx.body = "<h1>Error Login</h1><br/><a href='/'>重新登录</a>";
}
});
// 注意: koa-body 必须在 router 前先被注册使用
app.use(koaBody());
// 注册使用 koa-router
app.use(router.routes());
app.listen(3000, () => {
console.log("http://localhost:3000");
});
附加
使用 koa-body 来做文件上传,需要修改注册中间件时的选项,然后使用ctx.request.files.file
来获取文件
app.use(koaBody({
multipart: true,
formidable: {
maxFileSize: 1 * 1024 * 1024 // 设置上传文件大小最大限制,默认2M
}
}));
# 优化路由
以上的代码都是写在单个文件中然后直接运行的,这样会导致一个问题:
有的URL处理函数都放到app.js里显得很乱,而且,每加一个URL,就需要修改app.js。随着URL越来越多,app.js就会越来越长。代码过多时,会导致代码耦合。所以需要对路由处理的代码来进行优化
优化后的目录如下:
project
├─app.js
├─package.json
|—controllers
| ├─model.js ---------- 存放具体的业务方法
| └ index.js ---------- 只关注于路由的方法
app.js
const Koa = require("koa");
const koaBody = require("koa-body");
const Router = require("koa-router");
const controllers=require("./controllers");
const router = new Router();
const app = new Koa();
app.use(koaBody());
app.use(controllers(router));
app.use(router.allowedMethods());
app.listen(3000, () => {
console.log("http://localhost:3000");
});
controllers/index.js
const model = require("./model");
module.exports = (router) => {
router.get("/", model.index);
router.get("/hello/:name", model.hello);
router.post("/signin", model.signin);
return router.routes();
}
controllers/model.js
var index = async (ctx, next) => {
ctx.type = "text/html";
ctx.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
};
var signin = async (ctx, next) => {
var body = ctx.request.body;
var name = body.name || '';
var pwd = body.password || '';
console.log(`name: ${name} && pwd: ${pwd}`);
if (name == "koa" && pwd == "demo") {
ctx.body = "<h1>Success Login</h1>";
} else {
ctx.body = "<h1>Error Login</h1><br/><a href='/'>重新登录</a>";
}
};
var hello = async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
};
module.exports={
index:index,
signin:signin,
hello:hello
}
这样的优化虽然并不是最好的,但是在一定程度上做到了解耦,也有更好的方案,比如廖雪峰老师的教程。当然也有使用最新的es特性,使用类的装饰器来进行封装的方法,这里就不再多叙述。