HTTP Path 匹配和参数提取

0 条评论

给定一个 REST 的 Path 规则是: /orgs/<orgName>/apis/<apiName>/assets,其中尖括号包含的部分表示是一个可变的参数,参数一般情况下允许包含字母、数字、下划线。然后要求可以匹配符合规则的 HTTP URI Path 部分,并可以根据参数名称提取出参数的值来。

参考 bottle 项目的实现方案,将整个规则转换成一个正则表达式,然后利用 named group 特性,给定正则表达式捕获的分组名称来获取参数的值。

1. 把 /orgs/<orgName>/apis/<apiName>/assets 转换成 /orgs/(?:<orgName>[^/]+)/apis/(?:<apiName>[^/]+)/assets ,注意在 Java 7 后才支持这个正则表达式的写法,其中 (?:<orgName>[^/]+) 表示当前分组捕获结果可以用 orgName 来进行命名。为啥使用 named group 而不是直接按捕获分组顺序来查找,是因为情况再复杂一点的时候,正则表达式里的分组可能就很多很乱了,数也数不清顺序了。

2. 第一步转换成正则表达式的时候,同时把参数名称提取出来。

3. 正则表达式匹配,并根据参数名直接从正则表达式结果里获取参数

Java 代码样例:

  1. public static void main(String[] args) {
  2.     String rule = "/orgs/<orgName>/apis/<apiName>/assets";
  3.     String path = "/orgs/dev/apis/dts/assets";
  4.     Map params = match(rule, path);
  5.     System.out.println(params); // {apiName=dts, orgName=dev}
  6. }
  7. private static Map match(String rule, String path) {
  8.     StringBuilder pathRule = new StringBuilder();
  9.     List params = new ArrayList<>();
  10.     Pattern ruleSyntax = Pattern.compile("<(\\w*)>");
  11.     Matcher ruleMatcher = ruleSyntax.matcher(rule);
  12.     int offset = 0;
  13.     while (ruleMatcher.find()) {
  14.         int groupOffset = ruleMatcher.start();
  15.         pathRule.append(rule.substring(offset, groupOffset));
  16.         String groupName = ruleMatcher.group(1);
  17.         params.add(groupName);
  18.         // 拼接成 (?<name>[^/]+) 的正则表达式
  19.         pathRule.append("(?<").append(groupName).append(">[^/]+)");
  20.         offset = ruleMatcher.end();
  21.     }
  22.     if (offset < rule.length()) {
  23.         pathRule.append(rule.substring(offset, rule.length()));
  24.     }
  25.     Pattern pathPattern = Pattern.compile("^" + pathRule.toString() + "$");
  26.     Matcher pathMatcher = pathPattern.matcher(path);
  27.     Map result = new HashMap<>();
  28.     if (pathMatcher.matches()) {
  29.         for (String param : params) {
  30.             result.put(param, pathMatcher.group(param));
  31.         }
  32.     }
  33.     return result;
  34. }

相关日志 Relate Posts

  • 无相关日志
收藏与分享 : Twitter | Facebook | 微博 | 人人 | Google+ | PDF

发表留言(Ctrl+Enter提交)