Получение шаблона URL-адреса, который был поражен

У меня есть контроллер Spring MVC с несколькими API, я хочу получить URI API, который был поражен из внешнего интерфейса.

У меня есть фильтр, расширяющий OncePerRequestFilter, который перехватывает каждый вызов API, у фильтра есть метод, который принимает HttpServletRequest, HttpServletResponse и filterChain. Я могу получить uri, используя request.getRequestURI(), но в случае, если uri имеет переменные пути шаблона, скажем uri = "q/v1/ruleset/{rulesetId}" я получаю окончательный uri, например, API был атакован для rulesetid=23, uri, который я получаю от request.getRequestURI(), "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, сохранить их, а затем в фильтре сопоставить шаблон.

fiveelements 28.07.2019 15:26

Здравствуйте, Адитья. Вам нужны статистика/метрика или какая-либо другая операция, которую вы хотите выполнить?

Romil Patel 28.07.2019 16:14

@PatelRomil, да, в фильтре я записываю время выполнения API и количество API, затем отправляю статистику с помощью StatsD, основная проблема заключается в том, что с каждым значением переменной пути {rulesetid} создается новая метрика, в которой нет необходимости, вот почему я хочу шаблонный uri

Aditya Krishna Namdeo 28.07.2019 19:53

@AdityaKrishnaNamdeo Возможно, вы уже получили ответ, но для подсчета и статистики времени вы можете использовать администратор весенней загрузки, если хотите, дайте мне знать

Romil Patel 30.07.2019 11:59

@PatelRomil, когда я использовал пружинный привод для сбора метрик, привод предоставляет http-метрики по умолчанию для измерения времени и количества, но в случае statsD я не могу найти эту функцию, если эта функция существует, как вы говорите, пожалуйста, дайте мне знать

Aditya Krishna Namdeo 31.07.2019 09:04

@AdityaKrishnaNamdeo да, пружинный привод может собирать время, посчитайте с администратором весенней загрузки, вы можете легко увидеть это в форме графического интерфейса. Я отвечу на это в ближайшее время

Romil Patel 31.07.2019 09:07

Привет @AdityaKrishnaNamdeo, посмотри на ответ. Вы можете сосредоточиться на Spring Boot Admin

Romil Patel 31.07.2019 09:44
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
7
1 703
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Я сомневаюсь, что вы можете получить его в фильтре через существующий API. Однако вы можете предварительно отсканировать все аннотации @RequestMapping, сохранить их, а затем в фильтре сопоставить шаблон, чтобы получить желаемый результат.

Ответ принят как подходящий

Вы не сможете сделать это в фильтре, так как фильтр выполняется до обработчика.

Вы можете реализовать 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;
      }
}

Spring Boot Admin — простой в использовании с графическим интерфейсом

Другой способ — использовать Администратор весенней загрузки. Для этого нам нужно настроить клиент-сервер. Чтобы избежать ошибки, убедитесь, что версия для клиент-серверной зависимости одинакова. Мы можем добавить необходимую метрику из раскрывающегося списка, как показано на изображениях.

Вы можете COUNT, TOTAL_TIME для uri:/user/getEmployee/{employeeId} как 3, 0,2264027

Сторона клиента:

пом.xml

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

приложение.свойства

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

Сторона сервера:

приложение.свойства

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

пом.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);
    }

}

графический интерфейсhttp://локальный:6699/#/приложения


Программный подход

Если вы хотите добиться этого Если вы хотите добиться этого программно. Я даю подсказку здесь вы можете найти Все подробности здесь

@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 столько раз, сколько раз была конкретная конечная точка
    вызывается с конкретный статус
  • Чтобы получить среднее время выполнения endPoint, вы можете сделать TOTAL_TIME/COUNT как для конкретной конечной точки, так и для всего заявление

Более подробное объяснение

локальный: 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"
            ]
        }
    ]
}

Сделай это

    @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);
        }
    }

Вам нужно сначала выполнить filterChain.doFilter, прежде чем пытаться выполнить вызов request.getAttribute, поскольку этот атрибут устанавливается только позже в жизненном цикле запроса.

Вы можете попробовать это:

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

Другие вопросы по теме