Previous link-that is, the foundation of this article, refer to the koa,5 step handwritten a rough web framework
This article refers to the warehouse: Point me
Router is actually the path match, by matching the path, return to the user corresponding site content.
Take the example below, mainly by extracting req
the path
information, to match the current path, and give the ctx.body
assignment, return the corresponding interface. This process is not complicated, it is a process of matching paths. But this will be too bloated, and it is likely that more than one, it will be if...else...
dizzy.
app.use((ctx,next)=>{ //简易路由 let {path}=ctx if(path==="/"){ ctx.body="index" }else if(path==="/admin"){ ctx.body="admin" }else if(path==="/user"){ ctx.body="user" }})
This time the special processing path plug-in appears, write a Router
, dedicated to manage the path.
The function of router is altogether two:
- Matching paths
- return to corresponding page
If router is to be mounted on the app, then the syntax is this app.use(router.routes())
, which means:
- Router itself is a middleware
- To return a matching route, write a middleware that hangs
app
on the
Understand the router of the approximate, we began to write a step-by-router it!
STEP1 Creating router
First write the framework of router, a constructor, a get
method for configuring routing, a middleware that routers
becomes route matching is hung on the app.
class Router{ constructor(){} get(path,callback){} routers(){}}
When we get the route, we will definitely configure the page, then the class of this page must be added, each time get
, a page into the array.
class Page{ constructor(path,callback){ this.path=path this.callback=callback }}class Router{ constructor(){ this.pages=[] } get(path,callback){ this.pages.push(new Page(path,callback)) } routers(){}}
Because routing is the encapsulation of middleware, the usage is similar to app.use
the following:
router.get(path,(ctx,next){ ctx.body='xxx' next()})
Does it look familiar? The parameter in this get callback
is the middleware.
STEP2 Write a middleware that returns the middleware that matches the route
routers
Do three things:
- By filtering out the matching routes,
array.filter
you can do
- Combine to execute these routes
- Returns a middleware
compose(ctx,next,routers){ function dispatch(index){ if(index===routers.length) return next(); let router=routers[index] router(ctx,()=>dispatch(index+1)); } dispatch(0)}routers(){ let dispatch = (ctx,next)=>{ let path=ctx.path let routers=this.pages.filter(p=>{console.log(p.path);return p.path===path}).map(p=>p.callback) this.compose(ctx,next,routers) } return dispatch}
Everyone has a very familiar, and KOA in the application.js of the callback very much like. is actually a callback process, after encapsulation, it is easy for us to use.
STEP3 give the route a group.
When we write the route again, if all the full path is written, the feeling will be very verbose:
router.get("/admin",(ctx,next)=>{})router.get("/admin/login",(ctx,next)=>{})router.get("/admin/register",(ctx,next)=>{})...router.get("/user",(ctx,next)=>{})router.get("/user/login",(ctx,next)=>{})router.get("/user/register",(ctx,next)=>{})....
We give the route group, in fact the idea is very simple, is to give each path by a new router, and then the road by the use
method, the route to the collection together.
let admin=new Router()admin.get("/",(ctx,next)=>{ ctx.body="admin" next()})let user=new Router()user.get("/",(ctx,next)=>{ ctx.body="user" next()})//链式调用~let router=new Router()router.use("/admin",admin.routers()).use("/user",user.routers())app.use(router.routers())
Then the question comes, use
how to write it to combine these routers?? Let's start by analyzing use
the following features:
- Combining paths
- Joins the route into the array of the current object
use
There are two parameters in one path
, one router.routers()
middleware, but we need to router array objects, so we can do this:
routers(){ let dispatch = (ctx,next)=>{ ..... } dispatch.router=this return dispatch}
In the middleware on the dark rubbing to add a router object, will be passed out together, there is a very witty
With router
the array object, then use
this method is very well implemented, will page
loop a wave, join the current object pages
, just fine. It returns itself here and then happily uses the chained call.
use(path,middleware) { let router = this; middleware.router.pages.forEach(p => { router.get(path+p.path,p.callback) }); return router}
Step4 Last and not LEAST
Everyone needs to be aware, remember the last issue of async/await asynchronous?
If any operation other than routing is placed above the route, because the route only matches the path, the result is returned, and no async/await operation is performed.
So be sure to note:
This is valid. • The page returns AAA
app.use(async (ctx,next)=>{ await makeAPromise(ctx).then(()=>{next()})})...app.use(router.routers())
This is not valid and the page will not return AAA
... app.use (router.routers ()) App.use (Async (Ctx,next) =>{await next ()//wait for completion before continuing with ctx.body= "AAA"}) /code>