【问题标题】:Number of times REST API was called调用 REST API 的次数
【发布时间】:2020-04-22 13:39:04
【问题描述】:

如果我有 HTTP REST API:example /getCount

示例代码

@RestController
public class CountController {
    long count = 0;
    @Getmapping("/getCount")
    public long getCount(){
        count++; // Here is the problem, how to keep the latest count if the API was hit by multiple Application/clients
        return count;
    }
}

问题描述:任何应用/系统每次调用上述API,count都会加1,调用者实体可以得到准确的命中次数。

条件:它是一个开放的 API。需要指导如何实现它。 这是我唯一的问题陈述

【问题讨论】:

  • 如果系统重启,计数将被重置为0
  • 是的..它会的。但是我们必须保持旧的计数,下次任何应用点击 URL 时都会得到更新。这也需要小心。
  • 如果您需要计数,在应用重启后,您应该将计数存储在文件或数据库中的某个位置。
  • Microprofile Metrics Counter 可能很合适。
  • /getCount URL 命中时是否需要增加计数?还是您需要增加计数的每个请求?

标签: java json rest api


【解决方案1】:

由于 spring 默认为其 bean 提供 singleton 范围 - 您当前的代码即使适用于多个请求也应该可以工作,除非应用程序重新启动

另一种解决方案:使用Spring Boot Actuator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

并在请求处理方法中添加@Timed 注解。

现在您可以通过http://localhost:8080/actuator/metrics/http.server.requests获取统计数据

编辑 - 提供多客户端请求计数

在汇总和修改您的问题和不同的 cmets 之后 - 您似乎正在尝试实现每个用户的请求计数。我相信您需要使用HttpServletRequest 来跟踪客户端IP 地址,以便区分请求。据我所知Open API - 它没有提供这样的方法定义,所以你需要显式编程。

你修改后的代码应该是这样的,

@RestController
public class CountController {

    private static Map<String, Long> CLIENT_REQUEST_COUNT = new HashMap<>();

    @Getmapping("/getCount")
    public long getCount(HttpServletRequest request){

        String client = request.getRemoteAddr();

        if(Objects.nonNull(CLIENT_REQUEST_COUNT.get(client))) {
            long newCount = CLIENT_REQUEST_COUNT.get(client) + 1;
            CLIENT_REQUEST_COUNT.put(client, newCount);
            return newCount;
        }

        CLIENT_REQUEST_COUNT.put(client, 1);
        return 1;
    }
}

如果您想将您的请求计数与您的客户端对象(如果您有这样的对象)映射而不是使用 IP 地址 - 您需要检索当前用户并分别映射它们。

【讨论】:

    【解决方案2】:

    Java 通过 AtomicInteger 提供了很好的功能。这是一个线程安全的对象,您可以在调用计数器方法时依赖它来递增。

    第一:

    您需要将 Resource 类定义为 Singleton 并启动 AtomicInteger。

    private AtomicInteger count = new AtomicInteger();
    

    第二:

    您需要在您的 rest 方法中添加以下代码以将当前计数器加一。这将通过以下方法自动处理,

    count.incrementAndGet();
    

    最后:

    当您需要获取当前计数器时,您可以使用 REST 方法来获取如下详细信息,

    @GetMapping("count")
    public int getCount() {
        return this.count.get();
    }
    

    我希望这能澄清你的问题。

    【讨论】:

      【解决方案3】:

      信息不完整,但仍然尝试以我的方式回答这个问题。

      您是否需要在 /getCount URL 命中并在应用程序重启后继续计数器时增加计数。? 如果是,那么只需制作一个带有计数列的数据库表。启动应用程序时将此值加载到一个变量中,并每次增加此值。
      但我不希望你这样做!

      您是否需要增加每个 URL 请求的计数,但在应用程序重新启动/关闭时不希望以前的历史记录?
      在这种情况下,SPRING Actuator 是很好的实现方式。您无需为此编写代码。
      使用 Shekhar Rai 答案或Counter Metrics for Rest Api's in SpringBoot

      您是否需要增加每个 URL 请求的计数,并在应用程序重新启动后继续计数。
      在这种情况下,请为保持计数器创建数据库表,因为您需要在重新启动应用程序后继续计数器。
      在过滤器中,创建小线程以使数据库命中增加此计数器。线程因为这个任务不是高优先级所以不应该干扰主任务。

      【讨论】:

      • 但是假设我有 1000 个唯一客户,为此 api 被触发。我怎么知道它被触发了多少次
      • 意味着您需要跟踪每个用户的点击数?
      • 如果您需要跟踪每个唯一用户的点击次数,那么请制作 table("user","count")。在过滤器中获取会话并从会话中获取用户。如果用户未注册或未在您的系统中,则获取 IP 地址并根据 IP 地址存储计数。
      【解决方案4】:

      如果你想要如下的计数器行为,你可以使用静态类型

      • 计数器对于所有调用 API 的客户端都是通用的。
      • 一旦服务器重新启动,计数器将重新启动为 0。
      
      @RestController
      public class CountController {
          static long count = 0;
          @Getmapping("/getCount")
          public long getCount(){
              count++; // Here is the problem, how to keep the latest count if the API was hit by multiple Application/clients
              return count;
          }
      }
      

      如果您想为所有客户端使用不同的计数器,或者即使服务器关闭或重新启动也想保持计数器值,那么您需要使用 DB 来存储计数器。

      【讨论】:

      • count 字段不必是 static 字段 - 只要 CountController 的范围为 singleton,它就可以工作
      猜你喜欢
      • 2020-11-06
      • 1970-01-01
      • 2022-01-09
      • 2021-07-17
      • 2016-06-12
      • 2018-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多