Computer Science/Http 웹 지식

4. HTTP 메서드 - HTTP 웹 기본 지식

sh1mj1 2023. 1. 8. 13:43

이 글은 배민 기술이사 김영한 이사님의 인프런 강의 "모든 개발자를 위한 HTTP 웹 기본 지식" 을 기반으로 작성되었습니다. 문제 시 삭제 조치하겠습니다.

목차는 아래와 같습니다.

  • HTTP API 을 만들어보자
  • HTTP 메서드 - GET, POST
  • HTTP 메서드 - PUT, PATCH, DELETE
  • HTTP 메서드의 속성

HTTP API 을 만들어보자

a. 요구사항

회원 정보 관리 API를 만들어라.

1) 회원 목록 조회

2) 회원 조회

3) 회원 등록

4) 회원 수정

5) 회원 삭제

b. API URI 설계1

API 기능에 대응하는 직관적인 이름으로 URI 를 설계하면, 다음과 같이 URL을 모두 따로 만들어야 한다.

1) 회원 목록 조회 - /read-member-list

2) 회원 조회 - /read-member-by-id

3) 회원 등록 - /create-member

4) 회원 수정 - /update-member

5) 회원 삭제 - /delete-member

c. 이것은 좋은 URI 설계일까?

위에서는 동사와 명사를 함께 사용하여 URL 을 만드려고 합니다. 하지만 이것은 좋은 URI 설계는 아닙니다.

URI 설계에서 가장 중요한 것은 리소스 식별이 가능한지 입니다.

d. API  의 URI 고민

1) 리소스의 의미

  • 회원을 등록, 수정, 조회하는 것은 리소스가 아니다!!
  • 회원이라는 개념 자체가 리소스다!

2) 리소스 식별 방법

  • 회원을 등록, 수정, 조회하는 것을 모두 배제한다.
  • 회원이라는 리소스만 식별하면 된다. → 회원 리소스를 URI에 매핑

e. API URI 설계2

리소스 식별, URI 계층 구조 활용

 

1) 회원 목록 조회 /members

2) 회원 조회 /members/{id}

3) 회원 등록 /members/{id}

4) 회원 수정 /members/{id}

5) 회원 삭제 /members/{id}

 

회원이라는 리소스를 URI에 매핑하면, 회원 조회/등록/수정/삭제의 URI가 /members/{id}로 동일하여 구분할 수가 없다는 문제가 생긴다.

(참고) 계층 구조상 상위를 컬렉션으로 보고 복수단어 사용을 권장합니다. (member대신 members)

f. 리소스와 행위를 분리

앞서 말했듯이 가장 중요한 것은 리소스를 식별하는 것입니다.

 

1) 리소스와 해당 리소스를 대상으로 하는 행위를 분리

  • 리소스: 회원 → 명사
  • 행위: 조회, 등록, 삭제, 변경 → 동사

2) URI로 리소스를 표현해야 한다.

3) 리소스에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현된다.

HTTP 메서드 - GET, POST

HTTP 메서드클라이언트가 서버에 무언가를 요청할 때 기대하는 행위입니다.

최근에는 리소스라는 단어대신 representation 을 사용하는데, 아직 설명전이니 representation 대신 리소스를 사용하도록 하겠다.

 

<HTTP 주요 메서드 종류>

1) GET: 리소스 조회

2) POST: 요청 데이터 처리(주로 등록에 사용)

3) PUT: 리소스를 대체, 해당 리소스가 없으면 생성(파일을 폴더에 넣는 것과 비슷)

4) PATCH: 리소스 부분 변경(e.g 회원의 이름 변경)

5) DELETE: 리소스 삭제

 

<HTTP 기타 메서드 종류>

1) HEAD: GET과 동일하지만 메시지 부분(message body)을 제외하고, 상태 줄(status-line)과 헤더만 반환

2) OPTIONS: 대상 리소스에 대한 통신 가능 옵션(메서드)를 설명(주로 CORS에 사용)

3) CONNECT: 대상 자원으로 식별되는 서버에 대한 터널을 설정

4) TRACE: 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행

(참고) CONNECT, TRACE는 거의 사용하지 않음

 

a. GET

리소스 조회

  • 서버에 전달하고 싶은 데이터query(쿼리 파라미터/쿼리 스트링)을 통해서 전달
  • 메시지 바디를 사용해 데이터를 전달할 수 있지만, 지원하지 않는 곳이 많아 권장X

https://blog.kakaocdn.net/dn/uQWNu/btrDpQlC6zC/hN30NDkszBo43ezroeS1mK/img.png

b. GET 과정

1) 리소스 조회1 - 메시지 전달

 

클라이언트가 members/100 유저를 조회하기 위해 GET 방식으로 HTTP 요청 메시지를 서버에 전달한다.

https://blog.kakaocdn.net/dn/CvTLP/btrDnqgWfeK/czmJmJKeTMs7DKD8TaJMf0/img.png

 

2) 리소스 조회2 - 서버 도착

서버에 GET 메시지가 도착하면 서버는 GET 메시지를 해석하여 DB에서 /members/100 유저를 조회하여 JSON 메시지를 만든다.

https://blog.kakaocdn.net/dn/uXD5R/btrDqU9b2Cc/4FltnkxTdDG242MBVasuv0/img.png

 

3) 리소스 조회3 - 응답 데이터

서버는 리소스 조회에 성공했다는 의미로

  • status-line 에 200 OK,
  • header Content-Type,
  • message-body 에 /members/100을 조회한 결과(JSON)을 붙여 HTTP 응답 메시지를 만든다.

https://blog.kakaocdn.net/dn/myrJ0/btrDtuPtw90/iw5C7VkvcjPFW5ix3gwXYk/img.png

c. POST

요청 데이터 처리

  • 메시지 바디를 통해 서버로 요청 데이터 전달
  • 서버는 요청 데이터를 처리(메시지 바디를 통해 들어온 데이터를 처리하는 모든 기능 수행)
  • 주로 전달된 데이터로 신규 리소스 등록, 프로세스 처리에 사용

https://blog.kakaocdn.net/dn/d3AXAp/btrDthCOnmB/zx2KG2GLqLdEfXsWVvR9Sk/img.png

d. POST 과정

1) 리소스 조회1 - 메시지 전달

클라이언트가 유저를 등록하기 위해 message-body 에 유저 데이터를 담아서 POST 방식으로 HTTP 요청 메시지를 서버에 전달한다.

(POST로 /members에 요청이 들어오면 서버는 데이터를 저장한다는 것을 미리 약속해놓는다)

https://blog.kakaocdn.net/dn/O85JL/btrDvMbghKR/YHImEBXiUcdqT9i140EINK/img.png

 

2) 리소스 조회2 - 서버 도착

서버에 POST 메시지가 도착하면 서버는 POST 메시지를 해석하여 DB에 데이터를 등록하고 신규 리소스 식별자를 생성한다.

https://blog.kakaocdn.net/dn/oquvQ/btrDqUBnGoL/dx5dYenKKptSIySmVDnf31/img.png

 

3) 리소스 조회3 - 응답 데이터

서버는 데이터 등록을 성공했다는 의미로

  • status-line 201 Created,
  • header Location: 리소스가 생성된 신규 URI 경로(/members/100),
  • message-body 에 등록된 리소스(JSON)을 붙여 HTTP 응답 메시지를 만든다.

https://blog.kakaocdn.net/dn/bQTtK3/btrDmVIj6hP/MbB4Wp2SOK1Npf20hNp6WK/img.png

 

e. POST는 요청 데이터를 어떻게 처리한다는 뜻일까? (예시)

POST 메서드는 대상 리소스가 리소스의 고유한 의미 체계에 따라 요청에 포함된 표현을 처리하도록 요청한다.

 

<POST가 사용되는 곳>

 

1) HTML 양식에 입력된 필드와 같은 데이터 블록을 데이터 처리 프로세스에 제공

  • HTML FORM에 입력한 정보로 회원 가입, 주문 등에서 사용

2) 게시판, 뉴스 그룹, 메일링 리스트, 블로그 또는 유사한 기사 그룹에 메시지 게시

  • 게시판 글쓰기, 댓글 달기

3) 서버가 아직 식별하지 않은 새 리소스 생성

  • 신규 주문 생성

4) 기존 자원에 데이터 추가

  • 한 문서 끝에 내용 추가하기

→ 이 리소스 URI에 POST 요청이 오면 요청 데이터를 어떻게 처리할지 리소스마다 따로 정해야 함 (정해진 것이 없음)

 

<POST 정리>

1) 새 리소스 생성(등록)

  • 서버가 아직 식별하지 않은 새 리소스 생성
  • 주로 이 목적으로 많이 사용

2) 요청 데이터 처리 (중요!)

  • 단순히 데이터를 생성, 변경하는 것을 넘어서 프로세스를 처리해야하는 경우

e.g. 주문에서 결제 완료 → 배달시작 → 배달완료 처럼 단순히 값 변경을 넘어 프로세스 상태가 변경되는 경우

  • POST의 결과로 새로운 리소스가 생성되지 않을 수도 있음
(참고) 기본적으로 리소스만을 가지고 URI를 설계하는 것이 이상적이지만,
어쩔 수 없는 경우 컨트롤 URI (동사가 포함된 것)로 설계한다. (start-delivery 처럼 동사가 어쩔 수 없이 들어갈 수 있음)
e.g. POST/orders/{orderId}/start-delivery (컨트롤 URI)

 

3) 다른 메서드로 처리하기 애매한 경우

e.g. JSON으로 조회 데이터를 넘겨야하는데, GET 메서드를 사용하기 어려운 경우 POST의 message-body에 조회 데이터를 넘긴다.

데이터를 조회할 때는 최대한 GET을 쓰고 그 외에 데이터가 변경되거나 프로세스가 진행되는 어쩔 수 없는 경우, POST를 써도 됩니다!

HTTP 메서드 - PUT, PATCH, DELETE

a. PUT

리소스 대체

  • 리소스가 있으면 대체(덮어씀)
  • 리소스가 없으면 생성

중요한 점은 클라이언트가 리소스를 식별한다는 것이다!! 이것이 POST 와의 차이이다.

  • 클라이언트가 리소스 위치를 알고 URI 지정(POST와 차이점)
  • POST) /members :→ 클라이언트는 리소스 위치 모름
  • PUT) /members/100 → 클라이언트는 리소스 위치 알고 URI 지정

a'. PUT 동작 과정

PUT은 리소스가 있으면 대체, 없으면 생성하는 2가지 경우가 존재한다.

 

<리소스가 있는 경우>

1) 리소스 대체1 - 메시지 전달

클라이언트가 /members/100에 리소스를 대체하기 위해 PUT 방식으로 HTTP 요청 메시지를 서버에 보낸다.

https://blog.kakaocdn.net/dn/E2Cg3/btrDvRDFcIz/Ijkf9qxABbRSzUhvltyNB1/img.png

 

2) 리소스 대체2 - 리소스 대체

서버에 /members/100 이 있으면, HTTP 요청 메시지의 message-body에 있는 데이터로 리소스가 대체된다.

https://blog.kakaocdn.net/dn/brC5s2/btrDoUWdV9p/bXnuaFzC95PNClemVqULMk/img.png

 

<리소스가 없는 경우>

1) 리소스 대체1 - 메시지 전달

클라이언트가 /members/100에 리소스를 대체하기 위해 PUT 방식으로 HTTP 요청 메시지를 서버에 보낸다.

https://blog.kakaocdn.net/dn/v6tyL/btrDtuhFAzn/Y23EwQ9QqphIHj4ZeJw4e1/img.png

2) 리소스 대체2 - 신규 리소스 생성

서버에 /members/100 이 있으면, HTTP 요청 메시지의 message-body에 있는 데이터로 신규 리소스가 생성된다.

https://blog.kakaocdn.net/dn/caARzn/btrDoTXkcMB/kijSkpq1ocJitD8oKICzek/img.png

 

a''. PUT은 리소스를 완전히 대체한다!

1) 리소스를 완전히 대체한다1

age의 값만 변경하기 위해 message-body에 username은 빼고 변경할 age 값만 담아서 보낸다.

https://blog.kakaocdn.net/dn/bmfKIu/btrDnqBfmUS/V9UKysr5lNXrAHOHqpOJn1/img.png

2) 리소스를 완전히 대체한다2

리소스를 덮어쓰기 때문에, message-body에 있는 age 값만 들어가고 username 필드가 삭제된다.!!!!

https://blog.kakaocdn.net/dn/EmY2J/btrDmWAvMyK/OCIOBai5NV7kDHFDc7VE20/img.png

 

b. PATCH

리소스 부분 변경

https://blog.kakaocdn.net/dn/ZRcIG/btrDnrAbY47/CNkgASFKwTHWhYSxLgkg8K/img.png

 

b'. PATCH 동작 과정

1) 리소스 부분 변경1

age의 값만 변경하기 위해 message-body에 username은 빼고 변경할 age 값만 담아서 보낸다.

https://blog.kakaocdn.net/dn/cdlb3r/btrDpPAnT3j/iJicYnFWGthzGhKMbpow01/img.png

2) 리소스 부분 변경2

리소스를 부분 변경하기 때문에, message-body에 있는 age 값만 변경된다.

https://blog.kakaocdn.net/dn/bPn81w/btrDthJEuam/6ww9PcrM7dC769h3HUtMJ1/img.png

c. DELETE

리소스 제거

https://blog.kakaocdn.net/dn/bmSW7s/btrDmXlPEZE/OUGB9tLZ5kWiiaq5naeDk0/img.png

c'. DELETE 동작 과정

1) 리소스 제거1

클라이언트가 /members/100에 있는 리소스를 삭제하기 위해 서버에 DELETE 방식으로 HTTP 요청 메시지를 보낸다.

https://blog.kakaocdn.net/dn/2ZIJw/btrDqVtBHDN/HHAZRKU4GUbl7wmPaLcBdk/img.png

2) 리소스 제거2

서버는 /members/100에 있는 리소스를 제거한다.

https://blog.kakaocdn.net/dn/IcZ6K/btrDoaLOXKH/B6GeopV550iT9UE3vKgKVK/img.png

<정리>

  • PUT은 완전히 리소스를 대체(덮어씀)할 때 사용하고 PATCH는 리소스를 부분 변경할 때 사용한다!!
  • 요청받은 리소스(URI)가 없을 때, PUT신규 리소스를 생성해주지만, PATCH리소스가 없다는 오류가 발생해야한다.
  • PUT /members/100 요청 → /members/100이 없으면 members/100 생성
  • PATCH /members/100 요청 → members/100이 없다는 오류 발생

(참고) 요즘에는 PATCH가 거의 다 지원이 되지만 혹시나 PATCH가 지원되지 않으면, POST를 사용한다.

HTTP 메서드의 속성

<HTTP 메서드의 속성>

1) 안전(Safe Methods)

2) 멱등(Idempotent Methods)

3) 캐시가능(Cacheable Methods)

https://blog.kakaocdn.net/dn/114GV/btrDuv2nj6N/OOkZ6Kwb0pDj42CwKyHID0/img.png

a. 안전(Safe)

호출해도 리소스를 변경하지 않는다

 

<안전 메서드>

1) 안전O: GET, HEAD

2) 안전X: POST, PUT, PATCH, DELETE

Q. 계속 호출하면, 로그 같은 것이 쌓여서 장애가 발생할 수도 있지 않은가?

A. 안전은 해당 리소스만 고려한다. 그런 부분까지 고려하지 않는다.

 

b. 멱등(Idempotent)

f(f(x)) = f(x)

클라이언트가 서버에 같은 요청을 여러 번 해도 결과가 똑같다.

(한 번 호출하든 두 번 호출하든 100번 호출하든 결과는 동일)

 

<멱등 메서드>

1) 멱등 O

  • GET: 몇 번을 조회하든 같은 결과가 조회된다.
  • PUT: 결과를 대체한다. 따라서 같은 요청을 여러 번 해도 대체된 결과는 같다.
  • DELETE: 결과를 삭제한다. 따라서 같은 요청을 여러 번 해도 삭제된 결과는 같다.

2) 멱등 X

  • POST: 멱등이 아니다! 같은 데이터를 계속해서 POST로 전송하면 서버에서 매번 새로운 리소스를 생성한다(아이디를 새로 발급)

e.g. 두번 호출하면 같은 결제가 중복해서 발생할 수 있음

(참고) HTTP 스펙은 POST가 멱등을 보장하지 않지만, 실제 개발하면서 POST에도 멱등을 보장하게 개발하는 것은 가능하다.
하지만 HTTP 스펙은 GET이 멱등을 보장해야하지만, 실제 GET이 멱등을 보장하지 않게 개발하는 것은 문제가 될 수 있다.

 

<활용>1) 자동 복구 메커니즘

  • 클라이언트가 DELETE를 요청했는데 서버에서 응답이 없을 때, 클라이언트는 요청이 잘 되었는지 모른다.

그래서 클라이언트가 DELETE를 자동으로 재시도한다. 같은 요청을 해도 결과는 같기 때문에, 문제가 되지 않는다.

 

2) 서버가 TIMEOUT 등으로 정상 응답을 못주었을 때, 클라이언트가 같은 요청을 다시 해도 되는가? 의 판단 근거

 

Q. 재요청 중간에 다른 곳에서 리소스를 변경하면, 처음 요청했을 때의 결과와 재요청 결과가 달라진다.
이렇게 되면 멱등이 아니지 않은가?

https://blog.kakaocdn.net/dn/bbTc5h/btrDoUvEKe6/y4aKtrJZQRrYUkm2TsrKL0/img.png

A. 멱등은 외부 요인으로 중간에 리소스가 변경되는 것까지는 고려하지 않는다.

c. 캐시가능(Cacheable) 중요!!

캐싱 개념

  • 캐싱(Caching)은 애플리케이션의 처리 속도를 높여준다.
    이미 가져온 데이터나 계산된 결과값의 복사본을 저장함으로써 처리 속도를 향상시키며, 이를 통해 향후 요청을 더 빠르게 처리할 수 있다. 대부분의 프로그램이 동일한 데이터나 명령어에 반복해서 엑세스하기 때문에 캐싱은 효율적인 아키텍처 패턴이다.
  • 사용자(client)가 웹 사이트(server)에 접속할 때, 정적 컨텐츠(이미지, JS, CSS 등)를 특정 위치(client, network 등)에 저장하여, 웹 사이트 서버에 해당 컨텐츠를 매번 요청하여 받는것이 아니라, 특정 위치에서 불러옴으로써 사이트 응답시간을 줄이고, 서버 트래픽 감소 효과를 볼 수 있다

 

응답 결과 리소스를 캐시해서 사용해도 되는가?

예를 들어, 웹 브라우저에서 굉장히 큰 이미지를 요청하면 다음에 또 같은 리소스 서버에 요청할 필요가 없다.

즉, 내 로컬 PC에 웹 브라우저가 리소스를 저장하고 이후에 같은 요청이 들어오면 서버에 요청을 하지 않는다.

 

<캐시가능 메서드>

1) 캐시O: GET, HEAD, POST, PATCH

  • 실제로는 GET, HEAD 정도만 캐시로 사용 (GET은 URL을 키로 해서 캐시하면되므로 쉬움)
  • POST, PATCH는 본문 내용까지 캐시 키로 고려하는 것이 구현이 쉽지 않아 거의 사용X