Lock 이란?

하나의 자원에 여러 요청이 들어올 때 데이터의 일관성과 무결성을 보장하기 위해 하나의 커넥션에게만 변경할 수 있는 권한을 주는 기능으로 동시성을 제어하기 위한 목적으로 사용됩니다.  간단한 예시를 보면서 이해해 보도록 하겠습니다.

사용자에게 송금하는 메소드 transfer 가 있습니다. 순서는 다음과 같습니다. 잔고조회 -> 잔고 + amount

 

사용자A사용자B가 동시에 사용자C에게 송금한다고 했을 때, 사용자A, 사용자B는 1000 씩 송금을 했으니 사용자C의 잔고가 4000이 될 것으로 예상했으나 최종잔고는 3000이 되었습니다. 이는 동시성 문제로 데이터의 일관성과 무결성이 보장되지 않아서 생기는 문제입니다. 오늘은 이 문제를 해결하는 Lock 에 대해서 알아보도록 하겠습니다.

 

 

Lock의 종류

1. Shared Lock (공유 락)

  • 읽기 작업을 위한 Lock
  • 여러 트랜잭션이 동시에 데이터를 읽을 수 있음
  • 다른 Shared Lock과는 호환되지만 Exclusive Lock과는 호환되지 않음
    • 읽기 작업 중일 때, 새로운 읽기 작업이 들어온 경우 -> 가능
    • 읽기 작업 중일 때, 새로운 쓰기 작업이 들어온 경우 -> 불가능 (쓰기 작업으로 멱등성 보장x)

2. Exclusive Lock (배타적 락)

  • 쓰기 작업을 위한 Lock
  • 한 번에 하나의 트랜잭션만 데이터를 수정할 수 있음
  • 다른 어떤 Lock과도 호환되지 않음
    • 쓰기 작업 중일 때, 새로운 읽기 작업이 들어온 경우 -> 불가능
    • 쓰기 작업 중일 때, 새로운 쓰기 작업이 들어온 경우 -> 불가능

 

그렇다면 호환되지 않은 Lock의 요청이 들어올 때 불가능하다고 했는데 어떤 상황이 벌어질까?

 

 

Blocking

호환되지 않은 Lock 이 들어올 경우 블로킹(Blocking)이 발생합니다. 새로운 Lock의 요청이 들어올 때, 이미 Lock이 선행되고있으면 선행되고있는 Lock이 종료될떄까지 대기하고있다가 종료가 되면 새로운 Lock을 획득해 진행하게됩니다.

 

위의 예시에 Lock을 적용한다면 순서는 다음과 같습니다.

사용자A -> transfer(사용자A, 사용자C, 1000) -> Exclusive Lock 획득 -> 사용자B -> transfer(사용자B, 사용자C, 1000) -> Blocking (사용자A의 Lock이 해제될 때까지 대기) -> 송금 -> Blocking 해제, Exclusive Lock 획득 -> 송금 

 

위에서 Shared Lock은 여러 Shared Lock과 호환된다고했습니다. 만약 100개의 트랜잭션에서 Shared Lock을 획득하고 있을때 1개의 Exclusive Lock 요청이 들어온다면 100개의 Shared Lock이 모두 해제될때까지 대기하게 됩니다. 또는 끊기지 않고 Shared Lock이 들어온다면 Exclusive Lock은 계속 획득하지 못하게 됩니다. 따라서 Lock을 설정하는 범위를 알맞게 설정하는 것이 중요합니다.

 

 

그 다음으로 두개의 자원에 대한 Lock을 다룰때는 어떤 문제가 생길 수 있을까요?

 

 

Dead Lock

두 개 이상의 자원에서 서로 Blocking 되어 영구적으로 접근할 수 없는 상태(교착상태)입니다.

 

위의 transfer 메소드에서 사용자의 잔고를 줄이는 로직추가하여 예시로 들어보겠습니다. 로직은 다음과 같습니다. 그림그리는 것보다 코드가 더 읽기 쉽고 이해하기 편하니 코드로 작성하겠습니다.

    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        // 잔액 확인 및 업데이트를 위해 Exclusive Lock
        User fromUser = userRepository.findByIdWithLock(fromId);

        // 수신자의 계좌에 Exclusive Lock
        User toUser = userRepository.findByIdWithLock(toId);

        // 송금 처리
        fromUser.withdraw(amount);
        toUser.deposit(amount);
    }

 

시간 사용자A
(사용자A -> 사용자B에게 100원 송금)
사용자B
(사용자B -> 사용자A에게 100원 송금)
1 사용자A 락 획득 사용자B 락 획득
2 사용자B 락 획득시도 (Blocking) 사용자A 락 획득시도 (Blocking)
3 대기 대기
4 Dead Lock

 

그러면 위의 코드에서 Dead Lock이 발생하지 않게 하기 위해서는 어떻게 해아할까요?

락 획득의 순서에서 일과성을 유지하는 것입니다.

    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        User fromUser, toUser;
        if (fromId < toId) {
            fromUser = userRepository.findByIdWithLock(fromId);
            toUser = userRepository.findByIdWithLock(toId);
        } else {
            toUser = userRepository.findByIdWithLock(toId);
            fromUser = userRepository.findByIdWithLock(fromId);
        }
        fromUser.withdraw(amount);
        toUser.deposit(amount);
    }

 

사용자A ID = 1

사용자B ID = 2 라고 했을 때,

시간 사용자A
(사용자A -> 사용자B에게 100원 송금)
사용자B
(사용자B -> 사용자A에게 100원 송금)
1 사용자A 락 획득 사용자A 락 획득시도 Blocking
2 사용자B 락 획득 대기
3 송금 (락 반환) 사용자A 락 획득
4 - 사용자B 락 획득
5 - 송금 (락 반환)

 

 

결론

동시성 문제와 대용량 트래픽을 공부하기 위해 한정 수량 쿠폰과 대기열을 만들어보는 와중에 DeadLock와 데이터 무결성에 문제가 생겼고, 이를 해결하는 과정에서 Lock에 대해서 공부하게되었습니다. 다음 글은 JPA Lock 전략과 JAVA synchrozied, 그리고 JMeter 에 대해서 작성하려고합니다.

이전에 Flutter로 도넛차트를 구현했었습니다. 이번에는 디자인툴인 피그마로 도넛차트 만드는법에 대해서 알아보겠습니다.

 

 

1. 원 도형 생성

Ellipse (O) 를 80x80 사이즈로 생성합니다.

 

2. Arc 설정

도형 오른쪽에 마우스를 올리면 Arc를 설정할 수 있습니다. 잡고 12시방향에 위치시켜줍니다.

 

2. Ratio 설정

 

이 상태가 되었으면 Ratio를 잡고 원 밖방향으로 끌어주어 80%를 맞춰줍니다.

 

 

3. Background

도형을 복사 붙혀넣기 해서 겹치게 만들고 뒤에 도형에 Sweep를 잡고 100%를 만들어 원을 만들어줍니다.

4. 차트 만들기

차트를 표시할 도형을 선택하고 색상을 선택합니다. radius를 주고싶다면 주면 됩니다.

 

 

5. 시작점 변경

 

 

시작점은 변경해줍니다 Start부분을 잡고 12시 방향으로 바꿔줍니다.

 

끝!

1. CORS란 무엇인가?

CORS(Cross-Origin Resource Sharing)는 웹 브라우저에서 외부 도메인 리소스를 안전하게 요청할 수 있도록 하는 표준 규약입니다. 프론트엔드와 백엔드가 분리하는데 있어 CORS에 대해서 반드시 짚고 넘어가야합니다. 그래서 온르은 CORS에 대해서 공부해보겠습니다.

 

 

 

2. CORS의 필요성

핵심은 외부로부터 리소스를 공유하는 것입니다. 요즘 웹 애플리케이션에 개발에서 백엔드와 프론트엔드를 구분하지 않고 개발하는 곳은 거의 없을 겁니다.

 

  • 프론트엔드와 백엔드의 분리
  • 마이크로서비스 아키텍처 도입
  • 외부 API 활용
  • SPA(Single Page Application) 개발 방식

이러한 상황에서 다른 출처(Origin)의 리소스를 안전하게 요청하고 사용할 수 있어야 했고, 이를 위한 표준이 바로 CORS입니다.

 

 

 

3. Same-Origin Policy

Same-Origin Policy는 웹 브라우저의 기본적인 보안 정책으로, 같은 출처에서만 리소스를 공유할 수 있도록 제한합니다.

출처(Origin)는 다음 세 가지 요소로 결정됩니다:

  • 프로토콜 (http, https)
  • 호스트 (domain)
  • 포트 번호
  • http://example.com/path1, https://example.com/path2 는 프로토콜이 다르므로 다른 출처로 간주됩니다.

 

 

4. CORS 동작 방식

CORS는 HTTP 헤더를 통해 동작합니다. 주요 헤더는 다음과 같습니다:

 

4-1. 요청 헤더

  • Origin: 요청을 보내는 출처
  • Access-Control-Request-Method: 실제 요청에서 사용할 HTTP 메서드
  • Access-Control-Request-Headers: 실제 요청에서 사용할 헤더

4-2. 응답 헤더

  • Access-Control-Allow-Origin: 허용된 출처
  • Access-Control-Allow-Methods: 허용된 HTTP 메서드
  • Access-Control-Allow-Headers: 허용된 헤더
  • Access-Control-Max-Age: 프리플라이트 요청 캐시 시간
  • Access-Control-Allow-Credentials: 인증 정보 포함 여부

 

5. CORS 요청의 종류

 

5-1. Simple Request

  • GET, HEAD, POST 중 하나의 메서드 사용
  • 허용된 헤더만 사용
  • Content-Type이 다음 중 하나:
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

 

5-2. Preflight Request

Simple Request 조건을 만족하지 않는 요청의 경우, 브라우저는 실제 요청 전에 OPTIONS 메서드를 사용한 예비 요청을 보냅니다.

 

5-3. Credentialed Request

인증 정보(쿠키, HTTP 인증)를 포함한 요청입니다.

 

 

 

6. Spring Security CORS 설정

Spring Security CORS 설정에 대해서 알아보겠습니다.

 

 

UrlBasedCorsConfigurationSource apiConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();

        // 허용할 출처(Origin) 설정
        // https://api.example.com 에서 오는 요청만 허용
        configuration.setAllowedOrigins(List.of("https://api.example.com"));

        configuration.setAllowedOriginPatterns(List.of(
            "https://*.example.com",     // example.com의 모든 서브도메인 허용
            "https://*.example.*.com",   // 더 복잡한 패턴 매칭도 가능
            "http://localhost:[*]"       // 로컬호스트의 모든 포트 허용
        ));

        // 허용할 HTTP 메서드 설정
        // GET과 POST 메서드만 허용 (PUT, DELETE, PATCH 등은 차단됨)
        configuration.setAllowedMethods(List.of("GET","POST"));

        // 허용할 헤더 설정
        // 모두 허용
        configuration.setAllowedHeaders(List.of("*"));

        // 클라이언트에게 노출할 헤더
        configuration.setExposedHeaders(List.of("Authorization"));

        // allowCredentials를 true로 설정할 경우, allowedOrigins에 "*"를 사용할 수 없습니다
        configuration.setAllowCredentials(true);

        // CORS 프리플라이트 요청의 캐시 시간
        configuration.setMaxAge(3600L);

        // URL 패턴별로 CORS 설정을 적용할 수 있는 객체 생성
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        // 모든 경로("/**")에 대해 위에서 설정한 CORS 설정을 적용
        source.registerCorsConfiguration("/**", configuration);


        return source;
    }

 

    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

        http.cors(cors -> cors
            .configurationSource(apiConfigurationSource())
        );
        
        return http.build();
    }

 

6-1. Preflight 란?

configuration.setMaxAge() 에 대해서 간단하게 알아보겠습니다.

  • 브라우저는 실제 요청 전에 OPTIONS 메서드를 사용하여 preflight 요청을 보냅니다
  • 이 요청으로 해당 출처가 안전한지, 어떤 메서드와 헤더가 허용되는지 확인합니다
  • 매 요청마다 preflight를 보내면 성능 저하가 발생할 수 있습니다

6-1-1. maxAge의 역할

// 예시: preflight 응답 헤더
Access-Control-Max-Age: 3600
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type

 

  • 브라우저가 preflight 응답을 캐시하는 시간을 지정
  • 캐시 기간 동안은 동일한 요청에 대해 preflight를 다시 보내지 않음
  • 서버 부하 감소와 성능 향상에 도움

6-1-2. 브라우저별 최대 제한 시간

// 브라우저별 최대 캐시 시간이 다름
Chrome: 2시간 (7200초)
Firefox: 24시간 (86400초)
Safari: 7일

 

 

6-1-3. 장점

  • 서버 부하 감소
  • 네트워크 트래픽 감소
  • 응답 시간 개선

6-1-4. 단점

  • CORS 정책 변경 시 캐시된 정책이 즉시 적용되지 않을 수 있음
  • 브라우저마다 다른 최대 제한으로 일관성 있는 동작을 보장하기 어려움

 

 

6-2. allowCredentials와 allowedOrigins 설정

allowCredentials를 true로 설정하고 allowedOrigins에 "*"를 함께 사용할 수 없는 것은 중요한 보안상의 이유 때문입니다.

 

credentials에는 쿠키, HTTP 인증 토큰과 같은 민감한 인증 정보가 포함됩니다. 그런데 allowedOrigins에 모든 도메인("*")의 접근을 허용한다면 악의적인 웹사이트에서 사용자의 인증정보를 이용해 요청을 보낼 수 있게 됩니다.

 

 

[CS][Spring Security] CSRF란?

CSRF란?CSRF Cross-Site Request Forgery의 약자로 인증된 사용자의 권한을 악용하여 해당 사용자가 의도하지 않은 요청을 웹사이트에 전송하는 공격 기법입니다. 공격자는 사용자가 이미 인증된 상태를

tmd8633.tistory.com

이에 대해서는 CSRF에 대해서 읽어보시기 바랍니다.

 

따라서 브라우저는 이러한 보안 위험을 방지하기 위해 allowCredentials(true)와 allowedOrigins("*")의 조합을 명시적으로 금지하고 있습니다. 이는 웹 보안의 기본 원칙인 "최소 권한의 원칙"을 따르는 것이며, 실수로 인한 보안 취약점 발생을 방지합니다.

 

 

 

7. 자주 발생하는 CORS 에러와 해결 방법

7-1. No 'Access-Control-Allow-Origin' header is present

  • 원인: 서버에서 Access-Control-Allow-Origin 헤더를 설정하지 않음
  • 해결: 서버에서 적절한 CORS 설정 추가

 

7-2. Method not allowed

  • 원인: 허용되지 않은 HTTP 메서드 사용
  • 해결: allowedMethods에 필요한 메서드 추가

 

7-3. Credentials flag is true, but Access-Control-Allow-Credentials is false

  • 원인: 인증 정보를 포함한 요청에 대한 서버 설정 미비
  • 해결: allowCredentials(true) 설정 추가

 

8. 보안 관련 고려사항

8-1. Origin 설정

  • "*" 대신 구체적인 도메인 지정
  • 신뢰할 수 있는 출처만 허용

8-2. 인증 관련

  • allowCredentials(true) 사용 시 구체적인 출처 지정 필요
  • 보안에 민감한 API의 경우 더 엄격한 CORS 정책 적용

8-3. 헤더 설정

  • 필요한 헤더만 허용
  • exposedHeaders 설정 시 최소한의 헤더만 노출

8-4. 캐시 설정

  • maxAge 값을 적절히 설정하여 불필요한 프리플라이트 요청 감소

 

9. 결론

CORS는 현대 웹 개발에서 필수적인 보안 메커니즘입니다. 올바른 CORS 설정은 웹 애플리케이션의 보안과 기능성을 모두 만족시킬 수 있습니다. 각 프로젝트의 요구사항과 보안 정책에 맞게 적절한 CORS 설정을 적용하시기 바랍니다.

'일반 > CS' 카테고리의 다른 글

[CS][Spring Security] CSRF란?  (0) 2024.12.12
Maven Central Repository에 라이브러리 등록하기  (0) 2024.09.19
[CS] MVC 패턴  (0) 2024.04.17
HTTP GET과 POST 차이  (0) 2024.01.25
URI와 URL의 차이점 (Feat : URN)  (0) 2024.01.21

CSRF란?

CSRF Cross-Site Request Forgery의 약자로 인증된 사용자의 권한을 악용하여 해당 사용자가 의도하지 않은 요청을 웹사이트에 전송하는 공격 기법입니다. 공격자는 사용자가 이미 인증된 상태를 악용하여 사용자의 의도와는 무관한 작업을 수행하게 만듭니다. 다시 말해 인증된 요청과 위조된 요청을 구분하지 못하고 서버에서 요청을 처리하여 문제가 생기는 것을 말하는데요. 웹 개발자라면 반드시 알아야하는 부분입니다. 오늘은 이것에 대해서 알아보도록 하겠습니다.

 

 

 

CSRF 공격

CSRF 공격에 대해서 예시와 함께 알아보도록하겠습니다.

 

예시로 은행 웹사이트에서 로그인한 사용자로부터 돈을 이체할 수 있는 Form이 있다고 가정하겠습니다.

<form method="post" action="/transfer">
    <input type="text" name="amount"/>
    <input type="text" name="account"/>
    <input type="submit" value="Transfer"/>
</form>

HTTP 요청은 다음과 같습니다.

POST /transfer HTTP/1.1
Host: bank.jours.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded

amount=10000&account=7654

 

 

다음은 은행 웹사이트에서 로그아웃하지 않고 위조된 웹사이트를 방문한다고 가정하겠습니다. 그 웹사이트에는 다음과 같은 HTML이 있습니다.

<form method="post" action="https://bank.jours.com/transfer">
    <input type="hidden" name="amount" value="100000"/>
    <input type="hidden" name="account" value="1234"/> <!-- 공격자 계좌번호 -->
    <input type="submit" value="Win Money!"/>
</form>

 

위조된 웹사이트에서 submit을 하면 공격자 계좌로 송금이 될겁니다. 이는 위조된 웹사이트가 사용자의 쿠키를 볼 수 없지만 은행과 관련된 쿠키는 여전히 남아 요청과 함께 전송되기 때문에 발생합니다. 더욱 큰 문제는 버튼을 클릭해 submit 하지 않아도 JavaScript를 사용하여 자동화하여 제출할 수 있다는 것입니다. 그렇다면 어떻게 이 문제를 해결할 수 있을까요?

 

 

CSRF 방어

 

읽기전용 메소드

CSRF를 방어하기위해서는 읽기전용 메소드가 선행되어야 합니다.

HTTP Method중 GET, HEAD, OPTIONS, TRACE 메소드는 반드시 읽기전용 메소드가 되어야합니다.

// 잘못된 예시 - GET으로 데이터 변경
@GetMapping("/user/delete/{id}")  // ❌ 절대 하면 안 됨
public void deleteUser(@PathVariable Long id) {
    userService.deleteUser(id);
}

// 올바른 예시 - POST로 데이터 변경
@PostMapping("/user/delete/{id}")  // ✅ 올바른 방법
public void deleteUser(@PathVariable Long id) {
    userService.deleteUser(id);
}

 

 

1. Synchrozier Token Pattern

form 안에 CSRF 토큰을 넣어주는겁니다. 그러면 서버는 토큰을 조회하여 값이 일치하지 않으면 요청을 거부할 수 있게됩니다. 핵심은 쿠키는 브라우저에서 자동으로 HTTP 요청에 포함되지만 CSRF 토큰이 브라우저에서 자동으로 포함되지 않는다는 것입니다.

 

<form method="post" action="/transfer">
    <input type="text" name="amount"/>
    <input type="text" name="account"/>
    <input type="hidden" name="_csrf" value="4bfd1575-3ad1-4d21-96c7-4ef2d9f86721"/>
    <input type="submit" value="Transfer"/>
</form>

 

HTTP 요청은 다음과 같습니다.

POST /transfer HTTP/1.1
Host: bank.jours.com
Cookie: JSESSIONID=randomid
Content-Type: application/x-www-form-urlencoded

amount=100000&account=7654&_csrf=4bfd1575-3ad1-4d21-96c7-4ef2d9f86721

 

<!-- Thymeleaf 에서 @{} 를 사용하면 자동으로 CSRF 토큰이 포함됨 -->
<form th:action="@{/login}" method="post">

 

 

SameSite

쿠키에 SameSite 속성을 지정하는 것입니다. 서버는 SameSite 속성을 지정하여 외부 사이트에서 오는 쿠키를 보낼지 여부를 정할 수 있습니다.

 

 

설정값 설명
Strict
  • 가장 엄격한 설정
  • 같은 도메인의 요청에서만 쿠키 전송
  • 외부 사이트에서의 모든 요청에 쿠키를 보내지 않음
  • 보안성은 가장 높지만, 사용자 경험을 해칠 수 있음
Lax
  • TOP-level 네비게이션(주소창에 직접 입력, <a> 태그 클릭)에서는 쿠키 전송 허용
  • POST, PUT, DELETE 등의 요청에서는 쿠키 전송 제한
  • Strict보다 유연하면서도 기본적인 보안 제공
None
  • 모든 크로스 사이트 요청에 쿠키 전송 허용
  • 반드시 Secure 플래그와 함께 사용해야 함
  • HTTPS가 필수

 

 

# application.properties
# strict, lax, none 중 설정
server.servlet.session.cookie.same-site=strict

 

Spring Boot 2.6.0 이상에서는 SameSite=Lax 가 Default입니다.

 

SameSite 주의점

  • 브라우저가 SameSite를 지원하지 않을 수 있습니다. 예전 브라우저를 사용한다면 SameSite가 지원되지 않을 수 있습니다.
  • strict 설정 시  social.jours.com - email.jours.com 과의 쿠키는 전송되지않습니다.

 

 

 

REST API의 CSRF 설정

출처 : https://docs.spring.io/spring-security/reference/features/exploits/csrf.html#csrf-protection-read-only

 

REST API에서는 CSRF를 disabled 해도 괜찮다고합니다. 왜냐하면 API 요청시 인증정보(Jwt, OAuth2, Client Key 등)를 포함하여 전송하기 때문에 불필요하게 CSRF 인증정보를 저장하지 않아도 되는 것입니다.

 

 

 

Spring Security 에서의 CSRF 설정

Spring Security 에서 CSRF를 설정할 수 있습니다. 기본적으로 CSRF 토큰을 지원합니다.

    @Bean
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

        http.csrf(Customizer.withDefaults());

        return http.build();
    }

 

csrf 설정 메소드

http.csrf(csrf -> {
    csrf
        // CSRF 완전 비활성화
        .disable()                     
        
        // 특정 경로 CSRF 검증 제외
        .ignoringAntMatchers("/api/**")  
        
        // RequestMatcher로 더 복잡한 조건으로 제외할 경로 설정
        .ignoringRequestMatchers(requestMatcher)  
        
        // CSRF 토큰 저장소 설정
        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        
        // 커스텀 CSRF 토큰 저장소 설정
        .csrfTokenRepository(new CustomCsrfTokenRepository())
        
        // CSRF 토큰 생성 요청 처리 경로 설정 (기본값: "_csrf")
        .csrfTokenRequestHandler(requestHandler)
        
        // 세션 속성 이름 설정 (기본값: "CSRF_TOKEN")
        .sessionAuthenticationStrategy(sessionAuthenticationStrategy)
        
        // CSRF 토큰 필터 이전에 실행될 필터 추가
        .requireCsrfProtectionMatcher(requestMatcher)
});
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) 는 JavaScript에서 CSRF 토큰을 사용 할 수 있도록 쿠키에 저장하는 것인데, 위에서 설명했듯이 API는 csrf.disabled() 해서 사용하는 것이 더 유용할 수 있습니다.

 

 

결론

CSRF 공격은 웹 애플리케이션의 중요한 보안 위협이지만, 적절한 방어 메커니즘을 구현함으로써 효과적으로 방어할 수 있습니다. 특히 CSRF 토큰, SameSite 쿠키 설정, 그리고 적절한 헤더 검증을 조합하여 사용하는 것이 권장됩니다.

'일반 > CS' 카테고리의 다른 글

[CS][Spring Security] CORS에 대해서 알아보자  (0) 2024.12.16
Maven Central Repository에 라이브러리 등록하기  (0) 2024.09.19
[CS] MVC 패턴  (0) 2024.04.17
HTTP GET과 POST 차이  (0) 2024.01.25
URI와 URL의 차이점 (Feat : URN)  (0) 2024.01.21

이전 글

 

[Spring] JAVA로 금지어 검사기를 만들어보자

개요웹이나 앱을 개발하다보면 사용자가 입력한 데이터를 검증하는 과정에서 어쩔 수 없이 빼놓는게 금지어였습니다. 왜냐하면 사용할만한 라이브러리가 존재하지 않았기때문입니다. (제가 못

tmd8633.tistory.com

이전 글에서 만들었던 금지어 검사기를 Maven Central Repository에 등록해보겠습니다.

 

 

프로젝트 라이브러리화

@Configuration
@ComponentScan("ban.inspector")
public class WordInspectorAutoConfig {

}

 

이전 프로젝트를 그대로 배포해버리면 @Component 클래스들이 스캔범위 밖으로 벗어나기때문에 @ComponentScan 으로 해당 패키지를 설정해줍니다.

 

 

resources 하위에 META-INF 하위에 spring 폴더를 만듭니다.

org.springframework.boot.autoconfigure.AutoConfiguration.imports 라는 이름으로 file을 만듭니다.

위에 파일 안에 @ComponentScan 이 붙은 클래스의 패키지주소를 작성합니다.

org.springframework.boot.autoconfigure.AutoConfiguration.imports 내부에 작성된 config 클래스의 패키지주소

 

 

이렇게 설정하면 외부라이버리를 Component 로 손 쉽게 사용할 수 있습니다.

 

 

 

 

Maven Central Repository 등록하기

2024년 3월 12일부터 issues.sonatype.org는 폐쇄되어 모든 등록은 중앙 포털을 통해 이루어지도록 변경되었습니다. 기존 Nexus repository(OSSRH)로 올리는 방식을 사용하던 사용자는 기존 방식을 그대로 사용할 수 있지만, 신규 사용자라면 Maven Central을 통해서 라이브러리를 배포해야 합니다. 따라서 해당 게시글은 2024년 3월 12일 이후 적용되는 중앙포털을 통해 배포하는 방식입니다.

 

Maven Central Repository

Maven Central Repository는 Maven 프로젝트를 위한 공개 저장소입니다.

우리가 흔히 Maven Repository 에서 라이브러리를 찾아서 사용하는데 Maven Repository 는 라이브러리를 검색하는 곳이고, Maven Central Repository는 실제 파일을 등록하는 곳이라고 생각하시면 됩니다.

 

 

Maven Central

Official search by the maintainers of Maven Central Repository.

central.sonatype.com

 

 

1. namespace 만들기

 

회원가입을 하고 상단에 계정을 눌러 View Namespaces 를 눌러 이동합니다.

라이브러리를 github를 통해 배포하신다면 GitHub로 회원가입하는게 편합니다.

저는 github로 배포할것이기때문에 github로 회원가입했습니다.

 

 

GitHub로 회원가입을 하시면 github 주소로 자동생성됩니다.

 

 

 

 

2. GPG 키 생성

중앙 저장소에 라이브러리를 등록하기 위한 키 입니다.

 

 

2-1 설치

MAC은 아래 명령어로 설치하시면되고,

$ brew install gnupg

 

Windows 는

 

GnuPG - Download

Note that you may also download the GNU Privacy Guard from a mirror site close to you. See our list of mirrors. The table below provides links to the location of the files on the primary server only. These are the canonical release forms of GnuPG. To use t

gnupg.org

여기 들어가서 Gpg4WIn 을 다운받아 설치하시면 됩니다.

 

 

설치가 완료되었다면 gpg --version 을 통해 정상적으로 설치되었는지 확인합니다.

 

 

2-2 키생성

$ gpg --gen-key

키를 발급하는 과정에서 이름, 이메일, 비밀번호를 요구하는데 양식에 맞춰서 잘 작성하시면 됩니다.

비밀번호는 잊어버리지 않게 메모장에 작성해둡니다.

 

 

2-3 생성된 키 확인

$ gpg --list-keys --keyid-format short
[keyboxd]
---------
pub   ed25519/85683A34 2024-09-16 [SC] [expires: 2027-09-16]
      4520354F3D5C07DEDC90D716DDFE142685683A34
uid         [ultimate] xxxxxx Kim <xxxxxx@naver.com>
sub   cv25519/23DD4259 2024-09-16 [E] [expires: 2027-09-16]

키가 생성된 것을 확인할 수 있습니다. 여기 ed25519/85683A34 에서 뒤부분 8자리가 key ID가 됩니다. 

 

 

2-3 Key 등록

$ gpg --keyserver keyserver.ubuntu.com --send-keys 85683A34

맨 뒤 부분에 key ID를 넣어줍니다.

이 세개의 주소중 하나를 선택해서 등록해주시면 됩니다.

 

 

 

2-4 Pgp 파일 생성

$ gpg --export-secret-keys 85683A34 > /Users/user/Desktop/signing.pgp

pgp 파일을 생성할 위치를 뒤에 작성해줍니다.

 

 

 

3. 프로젝트 설정

 

build.gradle

plugins {
	...
	id "com.vanniktech.maven.publish" version "0.28.0"
	id 'signing' // GPG 서명을 위한 플러그인
}

plugins 안에 com.vanniktech.maven.publish 와 signing 을 추가합니다.

 

signing {
	sign publishing.publications
}

signing 을 추가합니다.

 

 

build.gradle 최상단에

import com.vanniktech.maven.publish.SonatypeHost

임포트를 해줍니다.

 

 

 

mavenPublishing {
	publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)

	signAllPublications()

	coordinates("io.github.kimseungwo", "wordinspector", "0.0.1") // 네임 스페이스, 라이브러리 이름, 버전 순서로 작성

	pom {
		name = "Maven Repository에 노출될 라이브러리명"
		description = "라이브러리 소개글"
		inceptionYear = "2024"
		url = "<https://github.com/KIMSEUNGWO/BanWordInspector>"
		licenses {
			license {
				name = "The Apache License, Version 2.0"
				url = "https://www.apache.org/licenses/LICENSE-2.0.txt"
				distribution = "https://www.apache.org/licenses/LICENSE-2.0.txt"
			}
		}
		developers {
			developer {
				id = "tmd8633"
				name = "이름"
				url = "https://github.com/KIMSEUNGWO"
			}
		}
		scm {
			connection = 'scm:git:github.com/KIMSEUNGWO/BanWordInspector.git'
			developerConnection = 'scm:git:ssh://github.com:KIMSEUNGWO/BanWordInspector.git'
			url = '<https://github.com/KIMSEUNGWO/BanWordInspector/tree/main>'
		}
	}
}

 

scm 작성법

connection = 'scm:git:github.com/[Github 사용자명]/[오픈소스 Repository 이름].git'
developerConnection = 'scm:git:ssh://github.com/[Github 사용자명]/[오픈소스 Repository 이름].git'
url = 'https://github.com/[Github 사용자명]/[오픈소스 Repository 이름]/tree/[배포 브랜치명]'

 

 

Maven Central Repository로 돌아와서 계정 - View Account - Generate User Token 클릭

OK 를 누르고 나온 username 과 password 를 메모장에 적어줍니다.

 

 

gradle.properties

mavenCentralUsername=[USER_NAME]
mavenCentralPassword=[USER_PASSWORD]
signing.keyId=[GPG_KEY_ID]
signing.password=[GPG_PASSWORD]
signing.secretKeyRingFile=[PGP_SIGNING_PATH]

프로젝트 루트폴더 내에 gradle.properties 를 생성해줍니다.

 

USER_NAME = Generate User Token 으로 생성된 username

USER_PASSWORD = Generate User Token 으로 생성된 password

GPG_KEY_ID = 2-3에서 생성된 키의 key Id

GPG_PASSWORD=2-2 키 생성시 등록한 비밀번호

PGP_SIGNING_PATH=2-4에서 생성된 pgp 파일의 절대경로

 

 

 

4. 배포

$ ./gradlew publishAllPublicationsToMavenCentralRepository

 

배포가 성공했다면

 

Maven Central Repository - 계정 클릭 - View Namespaces - Deployments 로 이동합니다.

 

VALIDATED 으로 상태가 변경되었다면 Publish 버튼이 활성화 됩니다. Publish를 눌러줍니다.

그럼 PUBLISHING 으로 변경되는데 수 분후에 PUBLISHED 로 변경되었다면 배포 성공입니다.

 

 

 

Maven Central Repository에서도 검색되고 Maven Repository에서도 검색이 됩니다. 이제 외부 라이브러리로 사용하시면 됩니다.

 

'일반 > CS' 카테고리의 다른 글

[CS][Spring Security] CORS에 대해서 알아보자  (0) 2024.12.16
[CS][Spring Security] CSRF란?  (0) 2024.12.12
[CS] MVC 패턴  (0) 2024.04.17
HTTP GET과 POST 차이  (0) 2024.01.25
URI와 URL의 차이점 (Feat : URN)  (0) 2024.01.21

이전 글

 

다대다(N:N) 관계는 왜 피해야할까?

다대다 관계 데이터베이스를 설계에서 다대다(N:N)관계는 피하는것은 일반적으로 권장되고있습니다. 하지만 자세한 설명이 추가되지않는다면 그 이유가 헷갈릴 수 있는데요. 이는 데이터의 무

tmd8633.tistory.com

 

이전 글에서 다대다(M:N) 관계를 해결하기 위해 1:N, N:1로 관계를 풀어주었습니다.

 

이를 통해 데이터 무결성과 중복성을 해결할 수 있었고, 유지보수와 확장에 대한 장점을 얻을 수 있었습니다.

하지만 이런 관계가 무한정 증가하다보면 관계가 복잡해지면서 이해하기가 어려워지는 단점이 존재합니다.

 

이번에는 1:N, N:1로써 해결하는것이 아닌 2진법을 통해 이 관계를 풀어보도록 하겠습니다.

 

 

2진법과 비트연산

컴퓨터를 조금이라도 공부해본사람이라면 2진법에 대해서 익숙하실겁니다. 따라서 간단하게 짚고 넘어가겠습니다.

 

2진법은 위와 같이 나타낼 수 있습니다. 다음은 이 수를 비트연산으로 표현해보겠습니다.

 

 

AND

두개의 2진수의 자리수가 둘다 1이면 1, 나머지는 0이되는 연산입니다.

 

 

OR

어느 하나라도 1이라면 1이되고, 둘다 0이라면 0이 되는 연산입니다.

 

 

XOR

두개의 값이 서로 다르면 1을 반환하고 그렇지 않으면 0을 반환합니다.

 

 

 

연산자는 더 있지만 이 글에서는 비트연산이 주제가 아니기때문에 생략하도록 하겠습니다.

 

그렇다면이 2진수 연산을 통해 어떻게 N:N관계를 풀수 있을까요?

 

 

 

2진법의 적용

기존의 1:N, N:1의 관계입니다.

1번의 홍길동 학생이 수강하는 과목은 JAVA, JS, Flutter, React 를 수강하고 그 과목코드는 1,2,3,4 입니다.

2번의 홍길순 학생이 수강하는 과목은 JAVA, JS 를 수강하고 그 과목코드는 1,2 입니다.

 

지금부터 한 단계씩 밟으며 관계를 정리해보겠습니다.

 

 

1. 과목코드 수정

현재 과목코드는 1 부터 오름차순으로 정의되어있습니다. 이를 2진수로 변경하겠습니다.

기존의 1,2,3,4 처럼 증가하는 수를 2의 지수로 표현하여 2의 0, 2의 1, 2의 2, 2의 3 로 나타내었습니다.

 

과목코드 과목명
0001 JAVA
0010 JS
0100 Flutter
1000 React

 

 

 

 

2. 수강테이블 합치기

우리는 위에서 잠깐 비트연산자 OR에 대해서 짚고 넘어갔습니다. 이 OR 연산자를 이용해서 수강테이블을 하나로 정리할 수 있습니다.

1번 홍길동의 수강목록 0001 + 0010 + 0100 + 1000 = 1111

2번 홍길순의 수강목록  0001 + 0010 = 0011

 

학번 수강코드
1 15 ( = 1111b)
2 3 ( = 0011b)

 

 

 

3. 수강테이블 삭제

학생과 수강 테이블간의 관계가 1:N에서 1:1로 변경되었습니다. 따라서 수강테이블을 삭제하더라도 1:N관계가 유지되므로 삭제해도 무방합니다.

 

과목코드를 직접 매핑시키지 않고 이와같이 사용할 수 있습니다.

최종적으로 수강테이블이 사라져 깔끔해졌습니다.

 

 

 

실제로 어떻게 사용해야할까?

실제로 조회, 추가, 삭제를 하려면 어떻게 해야할까요? 하나하나 알아봅시다.

 

아래부터 MySQL 기준으로 설명하겠습니다.

 

조회

홍길순 학생이 어떤과목을 수강하고 있는지 조회하려고합니다. 

 

SELECT *
FROM 학생
JOIN 과목 ON (학생.과목코드 & 과목.과목코드 = 과목.과목코드)

 

JOIN에서 비트연산을 해줍니다. 홍길순 학생의 수강하는 과목코드 3 ( = 0011b) 과 과목테이블의 과목코드 (0001, 0010, 0100, 1000)  가 같은지 확인해보면 됩니다. 

홍길순의 과목코드 첫번째자리는 JAVA의 1에 해당하는 위치입니다. 따라서 (홍길순의 과목코드) AND (JAVA 과목코드) = JAVA 과목코드 가 성립됩니다.

 

Flutter와 AND 연산을 했지만 그 결과는 0이고 이해 해당하는 과목은 존재하지 않으니 출력이 되지않습니다.

 

 

 

 

추가

홍길순 학생이 Flutter를 추가로 신청했을때 코드를 보겠습니다.

UPDATE 학생
SET 과목코드 = 과목코드 | ( SELECT 과목코드 FROM 과목 WHERE 과목명 = 'Flutter' )
WHERE 학번 = 2

 

서브쿼리에는 Flutter에 해당하는 과목코드만 존재하면 됩니다. 과목코드를 이미 알고있다면 서브쿼리를 사용하지 않고 바로 넣어줄 수 있습니다.

 

OR 연산자를 사용해서 기존 3 ( = 0011b) 에서 7 ( = 0111b) 로 업데이트 되었습니다. 

OR 연산의 장점은 만약 문제가 발생하여 Flutter 과목이 중복 수강이 되었어도, 중복으로 추가되지 않는다는것입니다. 

(0111 | 0100 = 0111)

 

 

 

삭제

이번엔 홍길동 학생이 JS 과목을 수강취소했을때의 코드입니다.

UPDATE 학생
SET 과목코드 = 과목코드 ^ ( SELECT 과목코드 FROM 과목 WHERE 과목명 = 'JS' )
WHERE 학번 = 2

XOR 연산을 통해 서로 다른값이어야 1을 반환하고 같은 값은 0으로 반환되었습니다.

 

 

 

결론

이 이진법을 이용한 테이블 관계매핑은 다대다 관계를 해소하기위한 보조 테이블들을 생성하지 않아 최적화에 도움이 되고, 데이터를 하나로 관리하는 편리함이 존재합니다.

하지만 단점으로는 데이터를 보관할 수 있는 한계가 존재한다는 점입니다.

데이터를 30개만 넣어도 값은 10억이 넘어가기 때문에 확장성을 고려해야하는 상황이라면 비트연산을 통한 매핑은 사용되어선 안됩니다.

오로지 한계가 정해져있는 부분에 사용되어야합니다.

 

최근 비트연산에 대해서 공부하고있는데 재미있어서 이렇게 글을 써보았는데, 혼자 공부하고 작성한 글이라 분명히 틀린부분이 존재할겁니다. 그대로 받아드리지 말고 참고만 해주시길 바랍니다. 틀린부분이 있다면 지적부탁드립니다.

'일반 > DB' 카테고리의 다른 글

[DB] Lock 이해하기  (0) 2025.01.15
다대다(N:N) 관계는 왜 피해야할까?  (1) 2024.02.29

MVC 패턴

MVC 패턴은 개발자라면 한번은 들어봤을겁니다. 오늘은 MVC 패턴에 대해서 알아보겠습니다.

 

 

 

MVC 패턴이란?

모델-뷰-컨트롤러(Model-View-Controller, MVC)는 소프트웨어 디자인 패턴 중 하나입니다. 이 패턴은 사용자 인터페이스(UI)로부터 비즈니스 로직을 분리하여 애플리케이션의 시각적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있습니다. 쉽게 말해 비즈니스 로직과 화면을 구분하는데 중점을 둔다는건겁니다.

MVC는 여러 파생되는 패턴을 가지고 있는데요. MVVM(Model-View-ViewModel), MVP(Model-View-Presenter), MVW(Model-View-Whatever)가 있습니다. 이 글에서는 MVC 에 대해서 알아보도록 하겠습니다.

 

 

 

Model, View, Controller의 관계

  • Model : 모델은 애플리케이션의 핵심 데이터와 비즈니스 로직을 나타냅니다. DB와의 상호작용, 데이터 처리 및 유효성 검사와 같은 작업을 수행합니다. 모델은 독립적으로 작동하며, 뷰와 컨트롤러와 직접적으로 통신하지 않습니다.
  • View : 사용자 인터페이스(UI)를 담당합니다. 모델에서 데이터를 받아 사용자에게 표시하고, 입력을 컨트롤러에 전달하는 역할을 합니다.
  • Controller : 사용자의 입력을 처리하고, 애플리케이션의 흐름을 관리합니다. 모델을 호출하여 데이터를 조작하거나 변경된 결과를 뷰에 전달하는 역할을 합니다.

출처 : wikipeida - 모델-뷰-컨트롤러

 

MVC 패턴을 설명할때 많이 사용하는 흐름도를 가져왔습니다.

 

이 개념을 웹에 적용한다면,

 

  1. USES : 사용자의 입력을 감지하고 Controller로 전달한다.
  2. MANIPULATES : Controller는 사용자가 요청한 웹 페이지를 보여주기 위해 Model 호출한다.
  3. UPDATES : 비즈니스 로직을 통해 데이터를 제어한 후 결과를 Controller에 반환하고 다시 Controller는 Model의 결과를 받아 View에 전달합니다.
  4. SEES : 데이터가 반영된 View가 사용자에게 보여준다.

 

 

MVC 패턴의 설계원칙

 

1. 각 구성 요소의 역할과 책임을 명확하게 구분

Model, View, Controller는 독립적으로 작동하고, 각각의 역할에 집중해야 합니다.

 

2. 구성 요소간의 결합도 최소화

구성 요소간의 직접적인 참조를 피해 의존성을 낮춰야합니다. 이를 통해 구성 요소를 독립적으로 개발, 수정, 테스트할 수 있습니다.

 

3. 코드의 재사용성과 확장성 고려

각 구성 요소는 독립적이고 재사용 가능한 모듈로 개발되어야합니다. 프로젝트의 규모가 코지거나 요구 사항이 변경되었을 때, 확장 및 수정이 용이해야합니다.

문제

EC2에 서버를 업로드하고 실행하는 과정에서 port 22: Operation timed out 이 발생하며 EC2 멈춤현상을 발견했습니다.

 

 

원인

EC2 프리티어의 RAM 용량은 1GB 정도라 메모리가 부족해 서버가 멈춰버리는 것이 원인이었습니다.

이 원인으로 SSH 접속이 불가능해져 인스턴스를 중지시키고 재시작해야하했었습니다.

 

 

해결

구글 검색을 해보니 SWAP 가상 메모리를 사용하여 메모리를 늘려줄 수 있다고 해서 찾아봤습니다.

이 가상 메모리는 메모리가 부족할 때 디스크 공간을 가져와서 메모리처럼 사용할 수 있게 해준다고합니다.

따라서 이 기능을 사용해 메모리부족 현상을 해결할 수 있을것 같았습니다.

 

 

 

과정

이미 EC2가 작동이 불가능하다면 먼저 인스턴스를 중지시키고 다시 실행시켜 ssh 접속을 하고 아래와 같이 진행해줍니다.

 

 

1. SWAP 메모리 추가

sudo dd if=/dev/zero of=/swapMem bs=128M count=16

2GB의 SWAP 메모리를 생성해줍니다.

 

 

2. 권한 부여

sudo chmod 600 /swapMem

 

 

3. SWAP 메모리를 SWAP 파일로 포맷

sudo mkswap /swapMem

 

 

4. SWAP 메모리 활성화

sudo swapon /swapMem

 

 

5. SWAP 메모리 자동 활성화

sudo vi /etc/fstab

해당 명령어를 작성하면 파일 편집에 들어갑니다.

  1. 'A' 를 눌러 파일 편집을 시작합니다.
  2. 작성되어있는 마지막 행 밑에 /swapfile swap swap defaults 0 0 를 추가로 작성합니다.
  3. ESC를 누르면 가장 밑에 INSERT 라고 표시됩니다.
  4. 콜론(:) 을 누르고 wq + 엔터를 누르면 파일 편집이 완성됩니다.

 

6. 메모리 확인

sudo free -h

2GB로 증가했다면 성공입니다.

 

EC2에서 서버를 다시 실행시키면 정상 작동 되는것을 확인할 수 있습니다.

다대다 관계

데이터베이스를 설계에서 다대다(N:N)관계는 피하는것은 일반적으로 권장되고있습니다. 하지만 자세한 설명이 추가되지않는다면 그 이유가 헷갈릴 수 있는데요. 이는 데이터의 무결성, 효율성, 유지보수 등 다양한 측면에서 중요한 이유가 있어 권장하지 않는것입니다.

 

 

 

다대다 관계란?

다대다 관계란 하나의 엔티티(Entity)가 다수의 다른 엔티티와 관계를 맺고 있는 상황을 나타냅니다. 예를들어, 학생과 강좌간의 관계에서 한 학생이 여러 강좌를 수강하고, 한 강좌에는 여러 학생이 수강할 수 있는것이 다대다 관계입니다.

 

 

다대다 관계는 왜 피해야할까?

위에 연관관계를 통해 완성된 테이블을 만들어보겠습니다.

 

1. 데이터 중복성과 무결성 문제

위 테이블에 기본키(PK)를 포함해서 데이터의 중복이 발생했고,  데이터의 무결성이 손상되었습니다. 이로 인해 학번만으로 데이터를 구분할 수 없어졌습니다. 

 

 

2. 유지보수 및 확장성

데이터의 추가 또는 변경이 일어난다면 중복된 데이터를 모두 수정 및 추가해야합니다. 예를 들어, 홍길동 학생의 학과가 '수학과'로 변경된다면 2군데 모두 수정해야하고, 학생 테이블에 성별을 추가한다면 중복데이터를 추가해야하는 일이 발생합니다. 

 

 

 

 

결론

학생과 과목테이블 사이에 수강테이블을 만들어 다대다 관계를 일대다(1:N), 다대일(N:1) 관계로 풀어주는 것으로 해결 할 수 있다.

 

 

다음 글을 읽어보는걸 추천드립니다.

 

 

다대다(N:N) 관계를 조금 더 쉽게 풀어보자 (2진법의 활용)

이전 글 다대다(N:N) 관계는 왜 피해야할까?다대다 관계 데이터베이스를 설계에서 다대다(N:N)관계는 피하는것은 일반적으로 권장되고있습니다. 하지만 자세한 설명이 추가되지않는다면 그 이유

tmd8633.tistory.com

 

'일반 > DB' 카테고리의 다른 글

[DB] Lock 이해하기  (0) 2025.01.15
다대다(N:N) 관계를 조금 더 쉽게 풀어보자 (2진법의 활용)  (0) 2024.05.18

GET과 POST의 차이

 

 

HTTP Method

HTTP Method는 클라이언트가 서버에 요청의 목적 및 종류를 알리는 수단입니다.

그 종류에는 GET, POST, PUT ,PATCH, DELETE.. 등 여러가지가 있습니다. 오늘은 가장 많이 쓰이는 GET과 POST에 대해서 알아보겠습니다.

 


GET

GET 방식은 주로 서버에서 리소스를 조회할때 사용됩니다.

 

특징

  • 캐시가 가능하다
    • 리소스를 요청할 때 웹 캐시가 요청을 가로채 리소스 복사본을 반환합니다. HTTP Header에서 cache-control 헤더를 통해 캐시 옵션을 지정할 수 있습니다.
  • 브라우저 히스토리에 남습니다.
  • GET은 SELECT 성향이 있어 서버에서 데이터 조회하는 용도로 활용됩니다.
  • URL에 데이터를 포함하여 요청할 수 있습니다. (쿼리스트링)
  • 데이터를 Header에 포함하여 전송합니다.

 

쿼리 스트링 또는 쿼리 파라미터

 

쿼리스트링은 ?로 시작하여 키(Key) = 값(Value) 형태로 전송할 수 있고 & 기호를 사용하여 다수의 데이터를 전송 할 수 있습니다. 다만 문제는 Header에 데이터가 노출되는 문제가 발생합니다. 


POST

POST 방식은 서버에 리소스를 처리할 때 사용됩니다. 주로 데이터를 추가하거나 수정하기 위해 사용됩니다.

 

특징

  • 캐시가 불가능 합니다.
  • 브라우저 히스토리에 남지 않습니다.
  • URL에 데이터를 노출하지 않고 요청할 수 있습니다.
  • 데이터를 Body에 포함하여 전송합니다.

GET과 POST의 차이

  • 사용목적
    • GET : 데이터 조회
    • POST : 데이터 생성 또는 수정
  • 데이터 위치
    • GET : Header
    • POST : Body
  • 멱등성(Idempotent) : 연산을 여러 번 하더라도 결과가 달라지지 않는 성질을 의미합니다.
    • GET : 멱등성 보장
    • POST : 멱등성 보장 X 

https://ko.wikipedia.org/wiki/HTTP

 

+ Recent posts