express的实现 | 6.路由参数

1,024 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

王志远,微医前端技术部

先看应用

应用规则:对于路由传参,通常有两种写法

  1. 请求时以?key=val的形式,获取时req.query
  2. 定义时以/:key1/:key2的形式,请求时以/val1/val2的形式,获取时req.params
app.get('/wzy1/:id/:name',function (req,res){
    console.log(req.params);
    res.end(JSON.stringify(req.params))
})

app.get('/wzy2',function (req,res){
    console.log(req.query);
    res.end(JSON.stringify(req.query))
})

实现思路

第一种,其实只要进行下以?截取,然后进行split,组装成为对象赋值在req.query属性上即可

重点实现第二种,关键是 1. 如何获取请求路径上的参数 2. 如何根据这种规定进行路由的匹配

很自然的,我们可以想到用正则,正则中的分组模式可以让我们获取到符合条件情况下的某部分的值

具体实现

首先看个例子

let configUrl = '/wzy/:id/:name';
let keys = [];


configUrl = configUrl.replace(/:([^\/]+)/g,function (){
    keys.push(arguments[1]);
    return '([^\/]+)'
})


let reg = new RegExp(configUrl);
let requestUrl = '/wzy/1/2';
let [,...args] = requestUrl.match(reg);
let params = {};
keys.forEach((key ,i) => {
    params[key] = args[i]
})

console.log(params);// {id: 1, name: 2} 

其实这种功能是有第三方包的,path-to-regexp,改写后如下

const {pathToRegexp} = require('path-to-regexp')
console.log(pathToRegexp);
let configUrl = '/wzy/:id/:name';
let keys = [];
regExp = pathToRegexp(configUrl,keys);
console.log(regExp, keys);

核心功能实现了,那我们开始接入express中,主要是改写路由匹配逻辑

接入正则

Layer.js

const pathToRegExp = require('path-to-regexp')

function Layer(path, handler) {
    this.path = path;
    this.regExp = pathToRegExp(this.path, this.keys = []);
    console.log(this.regExp, this.keys)
    this.handler = handler;
}
改写 macth

Layer.js


Layer.prototype.match = function(pathname) {
    // pathname = /user   /user
    if (this.path == pathname) {
        return true;
    }
    // 中间件只有开头就可以

    let r = pathname.match(this.regExp);
    if(r){
       let  [, ...matches] = r; // 正则匹配的结果 1 个是匹配到的整个结果 2 第一个分组 3 第二个分组
       this.params = {};
       this.keys.forEach((item, index) => {
           this.params[item.name] = matches[index]
       });
       return true;
    }
    if (!this.route) {
        if (this.path == '/') { // / 可以匹配任何路径
            return true;
        }
        // /user/add   
        return pathname.startsWith(this.path + '/')
    }
    // todo ...
    return false;
}