httpplugin支持url pathVariable解析和变量提取
一、背景
jvm-sandbox-repeater提供了http-plugin的基本实现,通过拦截javax.servlet.http.HttpServlet#service 方法从而拿到http的请求和返回,本次我们将扩展该插件实现,支持springMVC path url的变量解析和提取
首先我们定义一个controller, 带路径变量的
@RequestMapping("/api/test") @RestController public class TestController { @ResponseBody @RequestMapping("testPathVariable/{v}") public Result testPathVariable(@PathVariable String v) { System.out.println(v); return Result.buildSuccess("成功"); } }
我们请求该url, 执行shell命令
curl 'http://127.0.0.1:8080/api/test/testPathVariable/111'
那么对于这种的, 流量采集之后的路径是 /api/test/testPathVariable/111, 其中111其实是变量
因为我们涉及到很多配置,需要以路径来作为标识,因此理想的效果应该如下, 也就是 /api/test/testPathVariable/{v}
至此,应该理解我想要达到的效果了;
二、springMVC 关键代码解析
springMvc启动的时候,会初始化handlerMappings, HandlerMapping 是一个非常重要的组件,它的作用是将URL请求映射到相应的处理程序上。具体来说,HandlerMapping 会根据URL请求的路径、请求参数等信息,确定需要执行哪个处理程序,并将该处理程序返回给 DispatcherServlet。然后 DispatcherServlet 再将请求分配给相应的处理程序,处理程序处理完请求后,将结果返回给 DispatcherServlet,DispatcherServlet 再将结果返回给客户端。
其中handlerMapping有多种实现,见截图
我们通过debug发现,DispatcherServlet#doDispatch 中会调用 org.springframework.web.servlet.DispatcherServlet#getHandler 来获取执行链,最终会执行到org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#handleMatch里,其中有一段非常重要的逻辑跟每次业务有关系
再看 org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping#extractMatchDetails(org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition, java.lang.String, javax.servlet.http.HttpServletRequest)
private void extractMatchDetails( PathPatternsRequestCondition condition, String lookupPath, HttpServletRequest request) { PathPattern bestPattern; Map uriVariables; if (condition.isEmptyPathMapping()) { bestPattern = condition.getFirstPattern(); uriVariables = Collections.emptyMap(); } else { PathContainer path = ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication(); bestPattern = condition.getFirstPattern(); PathPattern.PathMatchInfo result = bestPattern.matchAndExtract(path); Assert.notNull(result, () -> "Expected bestPattern: " + bestPattern + " to match lookupPath " + path); uriVariables = result.getUriVariables(); request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, result.getMatrixVariables()); } //这里将相关的urlPattern都放到请求的扩展属性里了 request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern.getPatternString()); request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables); }
至此,我们就可以发现,直接从request的扩展属性中提取相应信息即可;
三、http plugin修改
修改com.alibaba.jvm.sandbox.repater.plugin.http.wrapper.WrapperTransModel,新增如下方法
public String getMatchPattern() { String matchPattern = (String) request.getAttribute("org.springframework.web.servlet.HandlerMapping.bestMatchingPattern"); return matchPattern; } public Map getUriVariables() { Map res = new HashMap(); if (request.getAttribute("org.springframework.web.servlet.HandlerMapping.uriTemplateVariables")!=null) { res.putAll((Map)request.getAttribute("org.springframework.web.servlet.HandlerMapping.uriTemplateVariables")); } return res; }
修改
com.alibaba.jvm.sandbox.repater.plugin.http.HttpStandaloneListener#assembleHttpAttribute, 将刚才的2个属性放进去即可