【问题标题】:Getting the template of URL that has been hit获取被点击的URL模板
【发布时间】:2019-12-06 01:09:59
【问题描述】:

我有多个 API 的 Spring MVC 控制器,我想获取从前端命中的 API 的 URI

我有一个扩展 oncePerRequestFilter 的过滤器,它拦截每个 api 调用,该过滤器具有接受 HttpServletRequest、HttpServletResponse 和 filterChain 的方法。 我可以使用request.getRequestURI() 获取uri,但如果uri 具有模板路径变量,可以说uri ="q/v1/ruleset/{rulesetId}" 我得到了最终的uri,例如rulesetid=23的API已经被命中,我从request.getRequestURI()得到的uri是 "q/v1/ruleset/23" 但我想要的是uri ="q/v1/ruleset/{rulesetId}", 有什么方法可以得到预期的结果吗,我知道,我总是可以通过一些操作得到想要的结果,但是我想让事情变得通用,请帮助

我有包含 API 的控制器

    @RequestMapping(value = "/ruleset/{rulesetid}", method = 
              RequestMethod.GET)
    public RuleSet getRuleSet(@PathVariable(value = "rulesetid") 
    final Long ruleSetId) {
         return storeMixin.getRuleSet(ruleSetId);
    }

过滤器

    @Component
    @Order(1)
    public class CatalogFilter extends OncePerRequestFilter {


    @Override
    protected void doFilterInternal(HttpServletRequest request, 
    HttpServletResponse response,FilterChain filterChain) throws 
      IOException, ServletException {


         long startTime = System.currentTimeMillis();
         filterChain.doFilter(request, response);
         long elapsed = System.currentTimeMillis() - startTime;
         String name = request.getRequestURI();
         String requestType = request.getMethod();


         Integer httpCode = response.getStatus();

      }

    }

【问题讨论】:

  • 我怀疑您是否可以通过 API 在过滤器中获取它。您可以预先扫描所有 @RequestMapping 注释,保留它,然后在过滤器中匹配模式。
  • 您好 Aditya,您的要求是统计数据/指标还是您想要执行的其他操作
  • @PatelRomil,是的,在过滤器中我正在记录 api 执行时间和 api 计数,然后使用 StatsD 推送统计信息,核心问题是路径变量 {rulesetid} 的每个值,它正在一个新的指标,这是不必要的,这就是我想要模板化 uri 的原因
  • @AdityaKrishnaNamdeo 也许您已经得到了答案,但是对于计数和时间统计,如果您愿意,可以使用 spring boot admin 让我知道
  • @PatelRomil 当我使用弹簧执行器收集指标时,执行器提供默认的 http 指标来测量时间和计数,但在 statsD 的情况下,如果此功能存在,我找不到此功能你是说请告诉我

标签: java spring-boot


【解决方案1】:

您将无法在过滤器中执行此操作,因为过滤器在处理程序之前执行。

您可以实现 HandlerInterceptor 并获取路径映射,如下所示

public class LogInterceptor implements HandlerInterceptor {

     @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
          String path = (String)request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
          System.out.println("path : " + path);
        return true;
      }
}

【讨论】:

    【解决方案2】:

    这样做

        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                throws ServletException, IOException {
            try {
                filterChain.doFilter(request, response);
            } finally {
                String patternMatch = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
            }
        }
    
    

    在尝试调用 request.getAttribute 之前,您需要先执行 filterChain.doFilter,因为该属性直到请求生命周期的后期才设置。

    【讨论】:

      【解决方案3】:

      你可以试试这个:

      String path = (String)request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
      

      【讨论】:

        【解决方案4】:

        我怀疑您是否可以通过现有 API 在过滤器中获取它。但是,您可以预先扫描所有 @RequestMapping 注解,保留它,然后在过滤器中匹配模式以获得所需的结果。

        【讨论】:

          【解决方案5】:

          Spring Boot Admin - 易于使用 GUI

          另一种方法是使用 Spring Boot Admin。为此,我们必须配置客户端-服务器。为避免该错误,请确保客户端-服务器依赖项的版本相同。如图所示,我们可以从下拉列表中添加所需的指标。

          您可以将 URI:/user/getEmployee/{employeeId} COUNT, TOTAL_TIME 设为 3, 0.2264027

          客户端:

          pom.xml

          <dependency>
               <groupId>de.codecentric</groupId>
               <artifactId>spring-boot-admin-starter-client</artifactId>
               <version>2.1.4</version>
          </dependency>
          

          application.properties

          spring.boot.admin.api-path=/instances
          spring.boot.admin.client.url=http://localhost:6699
          management.endpoints.web.exposure.include=*
          

          服务器端:

          application.properties

          server.port = 6699
          spring.boot.admin.server.url=http://localhost:8889
          

          pom.xml

           <dependency>
                   <groupId>de.codecentric</groupId>
                   <artifactId>spring-boot-admin-starter-server</artifactId>
                   <version>2.1.4</version>
              </dependency>
          

          添加@EnableAdminServer

          import de.codecentric.boot.admin.server.config.EnableAdminServer;
          
          @SpringBootApplication
          @EnableAdminServer
          public class AdminApplication {
          
              public static void main(String[] args) {
                  SpringApplication.run(AdminApplication.class, args);
              }
          
          }
          

          GUI http://localhost:6699/#/applications


          程序化方法

          如果您想实现这一点 如果您想以编程方式实现这一点。我在这里给出一个提示,您可能会发现 All Details Here

          @RequestMapping(path="/admin/count",method=RequestMethod.POST)
          public JSONObject count(@RequestParam(name="url") final String url)//@PathVariable(name="url") final String url
          {   
              String finalURL = "http://localhost:8080/actuator/metrics/http.server.requests?tag=uri:" + url + "";
              return sendRequestToURL(finalURL);  
          }
          

          我们可以使用 Spring Boot /actuator/metrics/http.server.requests 来获取所有执行的端点及其计数、异常、结果、状态、总时间等。

          如果您想查看特定端点的详细信息,则可以通过如下调用请求来完成

          localhost:8889/actuator/metrics/http.server.requests?tag=uri:<endPoint>
          localhost:8889/actuator/metrics/http.server.requests?tag=uri:/user/asset/getAllAssets
          localhost:8889/actuator/metrics/http.server.requests?tag=uri:/user/asset/getAllAssets&tag=status:200
          
          • 您将获得COUNT 作为特定端点的次数 叫
          • 您将获得COUNT 作为特定端点的次数
            特定状态调用
          • 要获得执行端点的平均时间,您可以这样做 TOTAL_TIME/COUNT 用于特定端点以及整体 应用

          More Detailed Explanation

          localhost:8889/actuator/metrics/http.server.requests

          {
              "name": "http.server.requests",
              "description": null,
              "baseUnit": "seconds",
              "measurements": [
                  {
                      "statistic": "COUNT",
                      "value": 3
                  },
                  {
                      "statistic": "TOTAL_TIME",
                      "value": 0.21817219999999998
                  },
                  {
                      "statistic": "MAX",
                      "value": 0.1379249
                  }
              ],
              "availableTags": [
                  {
                      "tag": "exception",
                      "values": [
                          "MethodArgumentTypeMismatchException",
                          "None"
                      ]
                  },
                  {
                      "tag": "method",
                      "values": [
                          "GET"
                      ]
                  },
                  {
                      "tag": "uri",
                      "values": [
                          "/{id}.*",
                          "/user/asset/getAsset/{assetId}",
                          "/user/asset/getAllAssets"
                      ]
                  },
                  {
                      "tag": "outcome",
                      "values": [
                          "CLIENT_ERROR",
                          "SUCCESS"
                      ]
                  },
                  {
                      "tag": "status",
                      "values": [
                          "400",
                          "404",
                          "200"
                      ]
                  }
              ]
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-08-22
            • 1970-01-01
            • 2019-08-28
            • 2011-04-15
            • 2011-06-17
            • 2012-07-12
            • 2015-01-29
            相关资源
            最近更新 更多