koajs / router

Router middleware for Koa. Maintained by @forwardemail and @ladjs.
MIT License
871 stars 176 forks source link

The router.use([path], ...fn) might not be correct for path array. #22

Closed lichaozhy closed 4 years ago

lichaozhy commented 5 years ago

node.js version: 10.15.3

npm/yarn and version: 6.5.0

koa-router version: 8.0.0

koa version: 2.7.4

Code sample:

const Koa = require('koa');
const KoaRouter = require('@koa/router');

const app = new Koa();
const rootRouter = new KoaRouter({
    prefix: '/api'
});
const childRouter = new KoaRouter();

childRouter.get('/test', ctx => {
    ctx.body = 'hello, world!';
});

rootRouter.get('/', ctx => {
    ctx.body = {
        foo: 'bar'
    };
}).use(['/foo', '/bar'], childRouter.routes());

app.use(rootRouter.routes()).listen(80);

Expected Behavior:

Request: [GET] http://127.0.0.1/api/foo/test or http://127.0.0.1/api/bar/test

Response: 200 text/plain hello, world!

Actual Behavior:

Response: 404 text/plain Not found

Additional steps, HTTP request details, or to reproduce the behavior or a test case:

But with string like,

const Koa = require('koa');
const KoaRouter = require('@koa/router');

const app = new Koa();
const rootRouter = new KoaRouter({
    prefix: '/api'
});
const childRouter = new KoaRouter();

childRouter.get('/test', ctx => {
    ctx.body = 'hello, world!';
});

rootRouter.get('/', ctx => {
    ctx.body = {
        foo: 'bar'
    };
}).use('/foo', childRouter.routes());

app.use(rootRouter.routes()).listen(80);

It works. It is correct when request get http://127.0.0.1/api/foo/test.

Additional clues

I watch the router instance stack rootRouter.stack in debugger. Here is the snapshot,

   rootRouter
    Router {opts: Object, methods: Array(7), params: Object, stack: Array(3)}
      [[StableObjectId]]:3
      methods:Array(7) ["HEAD", "OPTIONS", "GET", …]
      opts:Object {prefix: "/api"}
      params:Object {}
      stack:Array(3) [Layer, Layer, Layer]
        [[StableObjectId]]:4
        length:3
        __proto__:Array(0) [, …]
        0:Layer {opts: Object, name: null, methods: Array(2), …}
        1:Layer {opts: Object, name: null, methods: Array(2), …}
          [[StableObjectId]]:6
          methods:Array(2) ["HEAD", "GET"]
          name:null
          opts:Object {end: true, name: null, sensitive: false, …}
          paramNames:Array(0) []
*         path:"/api/bar/api/foo/test"
          regexp:/^\/api\/bar\/api\/foo\/test(?:\/(?=$))?$/i {keys: Array(0), lastIndex: 0}
          stack:Array(1) []
          __proto__:Object {match: , params: , captures: , …}
        2:Layer {opts: Object, name: null, methods: Array(2), …}
          [[StableObjectId]]:6
          methods:Array(2) ["HEAD", "GET"]
          name:null
          opts:Object {end: true, name: null, sensitive: false, …}
          paramNames:Array(0) []
*         path:"/api/bar/api/foo/test"
          regexp:/^\/api\/bar\/api\/foo\/test(?:\/(?=$))?$/i {keys: Array(0), lastIndex: 0}
          stack:Array(1) []
          __proto__:Object {match: , params: , captures: , …}
      __proto__:Object {acl: , bind: , checkout: , …}

It looks very funny at the line marked by '*' .