Javascript 对象路由映射



所以我需要构建一个可以将URL路径映射到目标服务器的对象,如下所示:

/api         :   http://apiserver:8000
/api/v1      :   http://apiv1server:8888
/api/v1/foo  :   http://foo:8080
/foo         :   http://foo:8080

function addRoute(path, server) {
  setRoute(path, server)
}
addRoute('/api', 'http://apiserver:8000')
addRoute('/api/v1', 'http://apiv1server:8888')

每个查找都应该匹配最具体的路由,所以我最初的想法是这样的对象:

 let map = {
   api: {
     v1: {
       default: 'http://apiv1server:8000',
       foo: 'http://foo:8080'
     },
     default: 'http://apiserver:8000'
   },
   foo: 'http://foo:8080'
 }

这样您就可以使用一个简单的查找函数,如下所示:

function lookup(path) {
  let result = null
  path.split('/').forEach(key => {
    result = map[key] || map[key].default
  })
  return result
}

但是尝试通过点(斜杠(符号设置对象已被证明非常困难,有什么想法吗?

还是有另一种更简单的方法可以做到这一点?

function lookup(path){
   let arr = path.split("/").splice(1);
   let m = {...map};
   arr.forEach((e)=>{
      m = m[e] || m.default;
   })
  return typeof(m) === "object" ? m.default : m;
}

你可以试试这个。

谢谢,由于我找不到设置路线的好方法,所以我转到了下面的递归方法:

let RouteMap = function (def) {
  this.defaultRoute = def
  this.map = {}
}
RouteMap.prototype = {
  lookup: function (path) {
    console.log('ROUTE MAP LOOKUP: ', path)
    if (path) {
      let parts = path.split('/')
      let p = parts.shift()
      if (this.map[p] instanceof RouteMap) {
        return this.map[p].lookup(parts.join('/')) || this.defaultRoute
      } else {
        return this.map[p]
      }
    } else {
      return this.defaultRoute
    }
  },
  set: function (path, val) {
    console.log('ROUTE SET: ', path, val)
    if (path) {
      let parts = path.split('/')
      let p = parts.shift()
      if (parts.length > 0) {
        this.map[p] = this.map[p] || new RouteMap()
        this.map[p].set(parts.join('/'), val)
      } else {
        this.map[p] = val
      }
    } else {
      throw new Error('Path is', path)
    }
  },
  addRoutesFromEnv: function (env) {
    for (let key in process.env) {
      if (key.startsWith('SERVICE_')) {
        let val = process.env[key]
        let parts = val.split('::')
        if (parts.length === 2) {
          this.set(parts[0], parts[1])
          // this.add(parts[0], parts[1]) // /api/v1::http://v1host:8000
        } else {
          console.warn('Invalid SERVICE_NAME environment variable: should be SERVICE_NAME=/path/to/proxy::http://host:port, ', key)
        }
      }
    }
    console.log('ROUTE MAP: ', JSON.stringify(this.map, null, 2))
  }
}
module.exports = RouteMap

最新更新