From 1c99dd839f3c08eb2606cab87c7d1e614867ca35 Mon Sep 17 00:00:00 2001 From: Yeongseo Na Date: Thu, 28 Nov 2024 22:30:55 +0900 Subject: [PATCH] =?UTF-8?q?[BE]=20refactor:=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C=20=EA=B4=80=EB=A0=A8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20(#983)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: request limit 코드 제거 * refactor: 로컬, 테스트의 request limit 변수 제거 --- .../requestlimit/RequestLimitInterceptor.java | 48 ------------ .../requestlimit/RequestLimitProperties.java | 8 -- .../requestlimit/RequestLimitRedisConfig.java | 34 --------- .../requestlimit/RequestLimitWebConfig.java | 20 ----- .../requestlimit/TooManyRequestException.java | 13 ---- .../global/GlobalExceptionHandler.java | 6 -- backend/src/main/resources/application.yml | 6 -- .../RequestLimitInterceptorTest.java | 75 ------------------- backend/src/test/resources/application.yml | 6 -- 9 files changed, 216 deletions(-) delete mode 100644 backend/src/main/java/reviewme/config/requestlimit/RequestLimitInterceptor.java delete mode 100644 backend/src/main/java/reviewme/config/requestlimit/RequestLimitProperties.java delete mode 100644 backend/src/main/java/reviewme/config/requestlimit/RequestLimitRedisConfig.java delete mode 100644 backend/src/main/java/reviewme/config/requestlimit/RequestLimitWebConfig.java delete mode 100644 backend/src/main/java/reviewme/config/requestlimit/TooManyRequestException.java delete mode 100644 backend/src/test/java/reviewme/config/requestlimit/RequestLimitInterceptorTest.java diff --git a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitInterceptor.java b/backend/src/main/java/reviewme/config/requestlimit/RequestLimitInterceptor.java deleted file mode 100644 index ef25b711e..000000000 --- a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitInterceptor.java +++ /dev/null @@ -1,48 +0,0 @@ -package reviewme.config.requestlimit; - -import static org.springframework.http.HttpHeaders.USER_AGENT; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; -import org.springframework.http.HttpMethod; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.HandlerInterceptor; - -@Component -@EnableConfigurationProperties(RequestLimitProperties.class) -@RequiredArgsConstructor -public class RequestLimitInterceptor implements HandlerInterceptor { - - private final RedisTemplate redisTemplate; - private final RequestLimitProperties requestLimitProperties; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { - if (!HttpMethod.POST.matches(request.getMethod())) { - return true; - } - - String key = generateRequestKey(request); - ValueOperations valueOperations = redisTemplate.opsForValue(); - valueOperations.setIfAbsent(key, 0L, requestLimitProperties.duration()); - redisTemplate.expire(key, requestLimitProperties.duration()); - - long requestCount = valueOperations.increment(key); - if (requestCount > requestLimitProperties.threshold()) { - throw new TooManyRequestException(key); - } - return true; - } - - private String generateRequestKey(HttpServletRequest request) { - String requestURI = request.getRequestURI(); - String remoteAddr = request.getRemoteAddr(); - String userAgent = request.getHeader(USER_AGENT); - - return String.format("RequestURI: %s, RemoteAddr: %s, UserAgent: %s", requestURI, remoteAddr, userAgent); - } -} diff --git a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitProperties.java b/backend/src/main/java/reviewme/config/requestlimit/RequestLimitProperties.java deleted file mode 100644 index 558378094..000000000 --- a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitProperties.java +++ /dev/null @@ -1,8 +0,0 @@ -package reviewme.config.requestlimit; - -import java.time.Duration; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "request-limit") -public record RequestLimitProperties(long threshold, Duration duration, String host, int port) { -} diff --git a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitRedisConfig.java b/backend/src/main/java/reviewme/config/requestlimit/RequestLimitRedisConfig.java deleted file mode 100644 index d8bb458a9..000000000 --- a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitRedisConfig.java +++ /dev/null @@ -1,34 +0,0 @@ -package reviewme.config.requestlimit; - -import lombok.RequiredArgsConstructor; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericToStringSerializer; - -@Configuration -@EnableConfigurationProperties(RequestLimitProperties.class) -@RequiredArgsConstructor -public class RequestLimitRedisConfig { - - private final RequestLimitProperties requestLimitProperties; - - @Bean - public RedisConnectionFactory redisConnectionFactory() { - return new LettuceConnectionFactory( - requestLimitProperties.host(), requestLimitProperties.port() - ); - } - - @Bean - public RedisTemplate requestLimitRedisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setConnectionFactory(redisConnectionFactory()); - redisTemplate.setValueSerializer(new GenericToStringSerializer<>(Long.class)); - - return redisTemplate; - } -} diff --git a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitWebConfig.java b/backend/src/main/java/reviewme/config/requestlimit/RequestLimitWebConfig.java deleted file mode 100644 index 19f3b2fe4..000000000 --- a/backend/src/main/java/reviewme/config/requestlimit/RequestLimitWebConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package reviewme.config.requestlimit; - -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -@RequiredArgsConstructor -public class RequestLimitWebConfig implements WebMvcConfigurer { - - private final RedisTemplate redisTemplate; - private final RequestLimitProperties requestLimitProperties; - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new RequestLimitInterceptor(redisTemplate, requestLimitProperties)); - } -} diff --git a/backend/src/main/java/reviewme/config/requestlimit/TooManyRequestException.java b/backend/src/main/java/reviewme/config/requestlimit/TooManyRequestException.java deleted file mode 100644 index 544fb5885..000000000 --- a/backend/src/main/java/reviewme/config/requestlimit/TooManyRequestException.java +++ /dev/null @@ -1,13 +0,0 @@ -package reviewme.config.requestlimit; - -import lombok.extern.slf4j.Slf4j; -import reviewme.global.exception.ReviewMeException; - -@Slf4j -public class TooManyRequestException extends ReviewMeException { - - public TooManyRequestException(String requestKey) { - super("짧은 시간 안에 너무 많은 동일한 요청이 일어났어요. 잠시 후 다시 시도해주세요."); - log.warn("Too many request received - request: {}", requestKey); - } -} diff --git a/backend/src/main/java/reviewme/global/GlobalExceptionHandler.java b/backend/src/main/java/reviewme/global/GlobalExceptionHandler.java index 161e43172..7724dd90e 100644 --- a/backend/src/main/java/reviewme/global/GlobalExceptionHandler.java +++ b/backend/src/main/java/reviewme/global/GlobalExceptionHandler.java @@ -22,7 +22,6 @@ import org.springframework.web.servlet.resource.NoResourceFoundException; import reviewme.global.exception.BadRequestException; import reviewme.global.exception.DataInconsistencyException; -import reviewme.config.requestlimit.TooManyRequestException; import reviewme.global.exception.FieldErrorResponse; import reviewme.global.exception.NotFoundException; import reviewme.global.exception.UnauthorizedException; @@ -51,11 +50,6 @@ public ProblemDetail handleDataConsistencyException(DataInconsistencyException e return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getErrorMessage()); } - @ExceptionHandler(TooManyRequestException.class) - public ProblemDetail handleDuplicateRequestException(TooManyRequestException ex) { - return ProblemDetail.forStatusAndDetail(HttpStatus.TOO_MANY_REQUESTS, ex.getErrorMessage()); - } - @ExceptionHandler(Exception.class) public ProblemDetail handleException(Exception ex) { log.error("Internal server error has occurred", ex); diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index aa0160b1f..45df6e2cb 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -37,9 +37,3 @@ cors: allowed-origins: - http://localhost - https://localhost - -request-limit: - threshold: 3 - duration: 1s - host: localhost - port: 6379 diff --git a/backend/src/test/java/reviewme/config/requestlimit/RequestLimitInterceptorTest.java b/backend/src/test/java/reviewme/config/requestlimit/RequestLimitInterceptorTest.java deleted file mode 100644 index 969040683..000000000 --- a/backend/src/test/java/reviewme/config/requestlimit/RequestLimitInterceptorTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package reviewme.config.requestlimit; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.springframework.http.HttpHeaders.USER_AGENT; - -import jakarta.servlet.http.HttpServletRequest; -import java.time.Duration; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; - -class RequestLimitInterceptorTest { - - private final HttpServletRequest request = mock(HttpServletRequest.class); - private final RedisTemplate redisTemplate = mock(RedisTemplate.class); - private final ValueOperations valueOperations = mock(ValueOperations.class); - private final RequestLimitProperties requestLimitProperties = mock(RequestLimitProperties.class); - private final RequestLimitInterceptor interceptor = new RequestLimitInterceptor(redisTemplate, requestLimitProperties); - private final String requestKey = "RequestURI: /api/v2/reviews, RemoteAddr: localhost, UserAgent: Postman"; - - @BeforeEach - void setUp() { - given(request.getMethod()).willReturn("POST"); - given(request.getRequestURI()).willReturn("/api/v2/reviews"); - given(request.getRemoteAddr()).willReturn("localhost"); - given(request.getHeader(USER_AGENT)).willReturn("Postman"); - - given(redisTemplate.opsForValue()).willReturn(valueOperations); - given(requestLimitProperties.duration()).willReturn(Duration.ofSeconds(1)); - given(requestLimitProperties.threshold()).willReturn(3L); - } - - @Test - void POST_요청이_아니면_통과한다() { - // given - given(request.getMethod()).willReturn("GET"); - - // when - boolean result = interceptor.preHandle(request, null, null); - - // then - assertThat(result).isTrue(); - } - - @Test - void 특정_POST_요청이_처음이_아니며_최대_빈도보다_작을_경우_빈도를_1증가시킨다() { - // given - long requestCount = 1; - given(valueOperations.get(anyString())).willReturn(requestCount); - - // when - boolean result = interceptor.preHandle(request, null, null); - - // then - assertThat(result).isTrue(); - verify(valueOperations).increment(requestKey); - } - - @Test - void 특정_POST_요청이_처음이_아니며_최대_빈도보다_클_경우_예외를_발생시킨다() { - // given - long maxRequestCount = 3; - given(valueOperations.increment(anyString())).willReturn(maxRequestCount + 1); - - // when & then - assertThatThrownBy(() -> interceptor.preHandle(request, null, null)) - .isInstanceOf(TooManyRequestException.class); - } -} diff --git a/backend/src/test/resources/application.yml b/backend/src/test/resources/application.yml index 9b8436a86..ccbe2e2ff 100644 --- a/backend/src/test/resources/application.yml +++ b/backend/src/test/resources/application.yml @@ -40,9 +40,3 @@ logging: cors: allowed-origins: - https://allowed-domain.com - -request-limit: - threshold: 3 - duration: 1s - host: localhost - port: 6379