Skip to content

Commit

Permalink
uuid 조회 및 생성 js로 변경 #17
Browse files Browse the repository at this point in the history
  • Loading branch information
InJun2 committed Jul 7, 2024
1 parent 00888c8 commit 5638216
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 29 deletions.
1 change: 1 addition & 0 deletions src/main/java/com/urlshortener/error/dto/ErrorMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum ErrorMessage {
NOT_FOUND_URL(HttpStatus.NOT_FOUND, "존재하지 않는 url"),

RATE_LIMIT_EXCEEDED(HttpStatus.BAD_REQUEST, "요청 횟수 초과"),
NOT_FOUND_CLIENT_ID_HEADER(HttpStatus.BAD_REQUEST, "요청 클라이언트 ID 헤더 없음"),

NOT_FINISH_DELETE_SIX_MONTHS_OLD_DATA(HttpStatus.NO_CONTENT, "6개월이 지난 데이터 삭제 실패"),

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.urlshortener.error.exception.url;

import com.urlshortener.error.dto.ErrorMessage;
import com.urlshortener.error.exception.BusinessException;

public class NotFoundClientIdHeader extends BusinessException {

public NotFoundClientIdHeader(ErrorMessage message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
package com.urlshortener.ratelimit.aspect;

import com.urlshortener.error.dto.ErrorMessage;
import com.urlshortener.error.exception.url.NotFoundClientIdHeader;
import com.urlshortener.error.exception.url.RateLimitExceededException;
import com.urlshortener.ratelimit.annotation.RateLimit;
import com.urlshortener.ratelimit.service.RateLimitService;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.UUID;

@Aspect
@Component
@RequiredArgsConstructor
public class RateLimitAspect {
private final RateLimitService rateLimitService;
private final HttpServletRequest request;
private final HttpServletResponse response;

/**
* UUID 사용한 요청 횟수 제한
Expand All @@ -31,44 +29,31 @@ public class RateLimitAspect {
*/
@Before("@annotation(rateLimit)")
public void checkRateLimit(RateLimit rateLimit) {
String clientId = getClientIdFromCookie(request, response);
String clientId = getClientIdFromCookie(request);

if (!rateLimitService.tryConsume(clientId, rateLimit)) {
throw new RateLimitExceededException(ErrorMessage.RATE_LIMIT_EXCEEDED);
}
}

// web Cookie uuid (요청 제한)
// uuid -> User class (uuid를 컨트롤러로 보내서 유저 클래스를 생성하고 id를 Short 넣어라)
// User class id -> controller shortUrl -> use ()
/**
* 쿠키 조회 및 쿠키가 없을 시 생성
* 쿠키 조회
*
* @param request 쿠키 조회, response 쿠키 등록
* @param request 쿠키 조회
* @return clientCookie UUID
*/
private String getClientIdFromCookie(HttpServletRequest request, HttpServletResponse response) {
private String getClientIdFromCookie(HttpServletRequest request) {
if (request.getCookies() == null) {
return createClientIdFromCookie(response);
throw new NotFoundClientIdHeader(ErrorMessage.NOT_FOUND_CLIENT_ID_HEADER);
}

return Arrays.stream(request.getCookies())
.filter(cookie -> "client-id".equals(cookie.getName()))
.map(Cookie::getValue)
.findFirst()
.orElseGet(() -> createClientIdFromCookie(response));
}

/**
* 쿠키 생성 및 쿠키 저장
*
* @param response 쿠키 등록
* @return clientCookie UUID
*/
private String createClientIdFromCookie(HttpServletResponse response) {
String clientId = UUID.randomUUID().toString();
Cookie cookie = new Cookie("client-id", clientId);
cookie.setPath("/");
cookie.setMaxAge(60 * 60 * 24 * 183);
response.addCookie(cookie);

return clientId;
.orElseThrow(() -> new NotFoundClientIdHeader(ErrorMessage.NOT_FOUND_CLIENT_ID_HEADER));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public class RateLimitService {
/**
* Client UUID 조회를 통한 요청 횟수 유효성 검사
*
* @param clientId Client UUID -> 일정 기간 내의 요청 횟수를 가져오기 위한 UUID key
* @param clientId -> Client UUID : 일정 기간 내의 요청 횟수를 가져오기 위한 UUID key
* @param rateLimit -> 요청 제한 횟수, 제한 시간 (Minutes) 설정
* @return boolean -> 요청 횟수 성공 여부
*/
public boolean tryConsume(String clientId, RateLimit rateLimit) {
Expand Down
57 changes: 54 additions & 3 deletions src/main/resources/templates/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,79 @@
$(document).ready(function() {
$('.form-signin').submit(function(event) {
event.preventDefault();
var originUrl = $('input[name="originUrl"]').val();
const originUrl = $('input[name="originUrl"]').val();
const clientId = getClientIdFromCookie();

$.ajax({
url: '/api/v1/short',
type: 'POST',
contentType: 'application/json',
headers: {
'client-id': clientId
},
data: JSON.stringify({ "originUrl": originUrl }),
success: function(response) {
$('.alert').remove();
var alertSuccess = '<div class="alert alert-success mt-4">' +
const alertSuccess = '<div class="alert alert-success mt-4">' +
'<a class="form-control" href="/' + response.data.replace("https://readys.link/", "") + '" target="_blank">URL: ' + response.data + '</a>' +
'</div>';
$('.form-group').after(alertSuccess);
},
error: function(response) {
$('.alert').remove();
var alertError = '<div class="alert alert-danger mt-4">'+JSON.parse(response.responseText).message+'</div>';
const alertError = '<div class="alert alert-danger mt-4">' + JSON.parse(response.responseText).message + '</div>';
$('.form-group').after(alertError);
}
});
});
});

// UUID 생성 함수
function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);

return v.toString(16);
});
}

// 쿠키 값을 가져오는 함수
function getCookie(name) {
let value = `; ${document.cookie}`;
let parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return parts.pop().split(';').shift();
}
}

// 쿠키를 설정하는 함수
function setCookie(name, value, days) {
let expires = "";
if (days) {
let date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}

// 클라이언트 ID를 쿠키에서 가져오거나 없으면 생성하여 설정하는 함수
function getClientIdFromCookie() {
let clientId = getCookie("client-id");
if (!clientId) {
clientId = createClientIdFromCookie();
}

return clientId;
}

// UUID를 생성하여 쿠키에 설정하는 함수
function createClientIdFromCookie() {
const clientId = generateUUID();
setCookie("client-id", clientId, 183); // 쿠키 유효기간 183일 설정

return clientId;
}
</script>
</head>
<body>
Expand Down

0 comments on commit 5638216

Please sign in to comment.