티스토리 뷰
HTTP 메서드
HTTP 메서드 종류
GET
- 일반적인 서버의 리소스 조회 시 사용
- 쿼리 스트링(Query String)에
{key}={value}
형태로 서버에 데이터를 전송할 수 있음 - 데이터가 URI에 그대로 노출되기 때문에 보안성에 취약함
- HTTP Message example
GET /api/users/1 HTTP/1.1
Host: example.com
💡 GET도 Message Body에 요청 데이터를 담아서 보낼 수 있지만 나중에 추가된 스펙이기 때문에 지원이 안될 수 있다.
POST
- 서버에 데이터를 전송해 새로운 리소스를 생성하거나 특정 프로세스를 처리하는 등 리소스마다 정해진 방식에 따라 처리
- Message Body에 다양한 방식으로 데이터를 담아서 보낼 수 있음(요즘은 JSON이 거의 표준)
- 애매하다 싶으면 POST를 사용하면 된다는 말이 있을 정도로 다양하게 사용됨
- HTTP Message example
POST /api/users HTTP/1.1
Host: example.com
Content-Type: application/json
{
"name": "tjdwls",
"email": "tjdwls@example.com"
}
PUT
- 서버에 리소스가 없으면 새로 생성하고, 있으면 업데이트(완전한 대체)
- Message Body에 리소스 필드들을 담아 전송할 때, 하나라도 빼먹으면 해당 필드 없이 리소스가 생성되므로 주의해야 함
- 새로운 리소스 생성 시 POST 메서드와의 차이점은 클라이언트가 리소스의 URI를 알고 지정해서 서버에 요청한다는 것
- HTTP Message example
POST /api/users/1 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"name": "tjdwls",
}
위 예시에서 email
필드를 빼먹고 요청하게 되면, 이 리소스는 email
필드 없이 생성되거나 기존의 데이터가 대체될 위험이 있다.
또한, /api/users/1
과 같이 이 리소스는 users의 1번 리소스라는 걸 클라이언트가 지정해서 요청하고 있다.
PATCH
- 서버의 리소스를 일부만 업데이트
- PUT과는 다르게 Message Body에 모든 필드가 아닌, 업데이트 하고 싶은 필드만 담아 요청하면, 서버는 해당 필드 데이터만 업데이트
- HTTP Message example
PATCH /api/users/1 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"email": "tjdwls2@example.com"
}
이처럼 PUT 보다는 리소스를 업데이터 하고자 할 때는 PATCH 메서드가 더 안전하면서도 의도에 맞고, 새로운 리소스를 생성하고 싶다면 POST 메서드를 사용하는게 나은 선택일 수 있다.
DELETE
- 요청한 리소스를 삭제
- HTTP Message example
DELETE /api/users/1 HTTP/1.1
Host: example.com
여기까지가 자주 사용하는 HTTP 메서드들이다. 이 외에도 몇 가지 더 있지만, 잘 사용하지 않기 때문에 그냥 이런게 있다 정도로 알아두면 좋다.
그 외 기타
HEAD
: 리소스의 헤더 정보만 조회할 때 사용(HTTP 응답 메세지에 Body가 없음)OPTIONS
: 서버가 특정 리소스에 대해 지원하는 HTTP 메서드 정보를 조회할 때 사용(CORS 설정 확인 등)
HTTP 메서드 속성
Safe(안전)
the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource - rfc9110.html
ex) GET
, HEAD
, OPTIONS
이 속성을 가지는 메서드는 클라이언트의 요청이 서버의 상태(리소스같은 데이터)를 변경하지 않는다.
예를 들어, GET
메서드는 단순히 리소스 조회를 할 뿐, 리소스를 변경하거나 삭제하지 않기 때문에 이 메서드는 안전하다는 의미다.
하지만 ‘수 많은 GET
요청이 반복되면 로그가 쌓이고, 이로인해 서버에 장애가 발생할 수 있지 않느냐’ 라는 의문을 제기할 수도 있다. 이를 표준 문서에서도 언급하고 있으며 정확히 정의해 준다.
This definition of safe methods does not prevent an implementation from including behavior that is potentially harmful, that is not entirely read-only, or that causes side effects while invoking a safe method. What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it. For example, most servers append request information to access log files at the completion of every response, regardless of the method, and that is considered safe even though the log storage might become full and cause the server to fail. - rfc9110.html
좋지 못한 구현, 완전한 read-only
가 아니라거나, 어떠한 외부 요인까지 safe 메서드의 정의에는 포함하고 있지 않다고 명시 되어 있으며, 이는 클라이언트의 요청 책임이 아니기 때문이라고 명시되어 있다.
핵심은 HTTP 메서드가 요청한 리소스의 상태를 변경시킬 의도가 있냐를 보면 될 것 같다.
Idempotent(멱등)
A request method is considered idempotent if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request. - rfc9110.html
ex) GET
, PUT
, DELETE
, HEAD
, OPTIONS
번역을 하면 오히려 어려워 보이는데, 속 뜻은 쉽다. 메서드의 동일한 요청을 여러 번 보내더라도 서버의 상태가 동일하게 유지되는 메서드다. 처음 요청한 결과가 100번을 요청한 결과와 같음을 보장한다.
Safe 메서드는 물론이고, PUT
메서드를 예로 들어보면, Message Body에 있는 데이터로 리소스를 덮어 씌우기 때문에 몇 번을 호출 하더라도 요청한 데이터를 가지는 리소스가 서버에 저장될 것이다.
그럼 왜 PATCH
는 멱등하지 않는 걸까? PATCH
메서드가 서버에서 리소스의 일부를 업데이트하는 데 사용되며, 동일한 PATCH
요청을 여러 번 보내는 경우 결과가 달라질 수 있기 때문이다.
PATCH /api/users/1 HTTP/1.1
Host: example.com
Content-Type: application/json
{
"operation": "increment",
"field": "counter"
}
위 예시에서 처럼 increment
옵션을 주면 counter
필드의 값이 1 증가하는 요청이라고 했을 때, 호출 횟수에 따라 counter
값이 계속 증가하기 때문에 이 리소스는 다른 상태가 된다.
멱등성을 이용하면, 멱등한 메서드의 요청이 TIMEOUT과 같은 이유로 실패했을 때, 재 요청을 서버에 보내는 자동 복구 시스템을 구축할 수 있다.
단, 외부 요인으로 인해 서버의 상태나 리소스가 변경되어 다른 결과를 얻게 되는 경우는 제외한다. 때문에 메서드가 멱등하다고 해서 항상 같은 결과를 얻게 되는 것은 아니기 때문에 그 상황이 멱등한지를 판단하고 위와 같은 시스템을 설계해야 한다.
Cacheable(캐시 가능)
캐시 가능한 메서드는 응답 결과를 클라이언트나 프록시 서버가 캐시할 수 있는 메서드다. 캐시된 응답은 동일한 요청에 대해 서버에 재요청 없이 캐시된 데이터를 반환할 수 있게 된다.
ex) GET
, HEAD
, POST
단, POST
는 응답에 Cache-Control
헤더를 추가해 줘야 캐시 기능을 사용할 수 있다.
POST
의 경우 위처럼 캐시를 제한적으로 사용할 수 있지만, 메서드 특성상 리소스 변경이 자주 되고, 프로세스의 흐름도 복잡한 경우가 많기 때문에 구현이 복잡해 진다. 그래서 실무에서는 보통 GET
과 HEAD
에서만 사용한다고 한다.
HTTP API 올바르게 설계하기
REST(Representational State Transfer)
HTTP API를 설계할 때 REST(REpresentational State Transfer) 아키텍처를 참고하면 좋다. REST는 6개의 기본 원칙을 가지고 있다. (https://restfulapi.net/)
REST에서 강조하는 점은 리소스를 명확하게 URI로 식별하며, CRUD(Create, Read, Update, Delete) 작업을 HTTP 메서드로 일관되게 표현하는 것으로, 보다 HTTP 표준의 장점을 최대한 활용하여 웹 서비스를 설계하는데 의의를 두고 있다.
HTTP 표준을 바탕으로 API를 설계해 보면 URI는 리소스, HTTP 메서드는 행위에 해당한다.
예를 들어 아래와 같은 URI는 안 좋은 설계다.
- domain/read-members
- domain/create-members
- domain/update-members
HTTP의 URI는 Uniform Resource Identifier로 리소스를 식별하는 유일한 식별자여야 한다. 위와 같은 경우 read-members를 식별자로 지정하게 되는데, 사실 members가 식별자고 read는 리소스를 조회한다는 행위일 뿐이다. 따라서 이를 분리시켜 줘야 한다.
- doamin/members
- doamin/members/{id}
그러면 URI에서 create와 update같은 행위를 어떻게 구분할 수 있을까? 이는 애초에 URI에서 구분하는 것이 아니다. HTTP가 이러한 행위들을 구분하도록 만들어 놓은 것이 위에서 봤던 HTTP 메서드들이다.
- doamin/members +
GET
→ 조회 - doamin/members +
POST
→ 생성… 등 - doamin/members/{id} +
PATCH
→ 수정
위처럼 리소스가 잘 분리되면 이상적이지만, HTTP 메서드의 개수가 제한적이고, 서비스 상황이 많아지게 되면 어쩔 수 없이 특정 행위(동사)를 포함하는 URI를 설계해야 할 수도 있다. 이러한 방식을 Controller 또는 Controll URI라고 한다. 실무에서는 프로세스가 상당히 복잡하기 때문에 생각보다 이러한 경우가 많다고 한다. 하지만 최대한 REST 방식으로 설계해 보는 것이 중요하며, 어쩔 수 없을 때 사용해야 한다.
정리하면,
- 리소스와 행위를 분리
- 리소스는 URI, 행위는 HTTP 메서드
- 안 되면 컨트롤 URI 사용
POST vs PUT
두 메서드는 리소스를 추가할 때 사용할 수 있지만 어떤 메서드를 선택하냐에 따라 설계가 달라지기 때문에 차이점을 알고 있어야 한다. 가장 큰 차이점은 “리소스를 어디서 관리하냐”에 있다.
POST
는 추가될 리소스 URI를 서버에서 생성 후 클라이언트에게 알려줌 → 컬렉션 방식PUT
은 추가될 리소스 URI를 클라이언트에서 생성 후 서버에게 알려줌 → 스토어 방식
💡 컬렉션(Collection) : 서버에서 관리하는 리소스 저장소 ex) /members
💡 스토어(Store) : 클라이언트에서 관리하는 리소스 저장소 ex) /files
예를 들어, POST
요청으로 유저를 추가할 때 이 유저가 몇 번째 유저인지, 어떤 URI를 가지게 되는지는 관심 없다. 하지만 PUT
은 추가하려는 유저의 URI를 온전히 다 알아야 요청을 보낼 수 있다.
- POST /members
- PUT /members/100
이처럼 클라이언트에서 리소스 저장소를 관리하기는 쉽지 않으며, 보통 리소스는 여러 개의 필드들을 가지고 있기 때문에, 이 데이터들을 모두 입력해 리소스를 생성하는 요청을 보내기는 쉽지 않다. 또한, PUT
은 멱등한 메서드기 때문에 리소스를 추가하는 기능 보다는 수정 및 대체한다는 가능으로 사용하는게 더 올바를 수 있다. 때문에 일반적으로 리소스 생성 시 POST
메서드를 주로 사용한다.
HTTP 상태 코드
HTTP 상태 코드(Status code)는 클라이언트가 보낸 요청에 대한 서버의 응답을 나타내는 3자리 숫자다. 이 코드는 서버가 요청을 성공적으로 처리했는지, 요청에 문제가 있었는지, 클라이언트가 어떤 조치를 취해야 하는지를 알려 준다.
1xx는 요청이 수신되어 처리 중이라는 의미인데 거의 사용되지 않기 때문에 생략한다.
2xx [Success]
요청이 성공했다는 의미로 사용된다.
- 200 OK : 정상적으로 조회가 완료
- 201 Created : 리소스가 정상적으로 생성. 생성된 URI를
Location
헤더에 담아 응답한다. - 202 Accepted : 요청이 수신 되었지만 아직 완료되지 않았음. 배치 처리에 이용된다.
- 204 No Content : 서버가 요청을 성공적으로 수행했지만, 응답 본문에 보낼 데이터가 없음.
3xx [Redirection]
클라이언트가 요청한 리소스가 다른 위치로 이동됐음을 나타내며, 클라이언트의 추가적인 조치가 필요함을 나타낸다. 이동해야 할 URI는 Location
헤더 값으로 나타낸다.
💡 Redirect : 웹 브라우저는 3xx 응답 결과에 Location
헤더가 있으면, 그 URI 위치로 자동 이동
영구적인 리다이렉트
- 301 Moved Permanently : 요청한 리소스의 URL이 영구적으로 변경되었으므로 리다이렉트. HTTP 메서드가
GET
으로 바뀌어 호출 및 메세지 본문도 삭제될 수 있음(명확하지 않음) - 308 Permanent Redirect : 301과 같은 기능이지만, 처음 요청한 HTTP 메서드와 메세지 본문을 유지(명확)
일시적인 리다이렉트
- 302 Found : 요청한 리소스가 일시적으로 다른 위치에 있으므로 클라이언트는 임시로 다른 URL을 사용해야 함.
GET
으로 바뀌어 호출되며 메세지 본문도 삭제될 수 있음(명확하지 않음) - 303 See Other : 302와 같은 기능이지만, 요청 메서드가
GET
으로 변경(명확) - 307 Temporary Redirect : 302와 같은 기능이지만, 처음에 요청한 HTTP 메서드와 메세지 본문을 유지(명확)
그 외
- 304 Not Modified : 서버는 리소스가 수정되지 않았다고 응답하며, 클라이언트는 로컬 캐시를 사용할 수 있음. 응답 메세지 본문을 포함하면 안된다.
- 305 Use Proxy : 요청된 응답에 프록시가 액세스해야 함을 나타냄
4xx [Client Error]
클라이언트의 요청에 문법 등의 오류가 있어 서버가 요청을 처리할 수 없는 경우
여러 번의 재시도를 하더라도 클라이언트의 요청을 수정하지 않는한 계속해서 실패하게 됨
- 400 Bad Request: 클라이언트의 요청이 잘못되었음을 나타냄. 예를 들어, 요청의 문법이 잘못되었거나 파라미터가 누락된 경우
- 401 Unauthorized: 클라이언트가 인증(Authentication)되지 않았음. 응답 메세지에
WWW-Authenticate
헤더와 함께 인증 방법을 보내줘야 함. 예를 들어, 로그인이 안된 경우 - 403 Forbidden: 서버는 요청을 이해했지만, 클라이언트가 요청한 리소스에 접근할 권한이 없어 거부함
- 404 Not Found: 클라이언트가 요청한 리소스를 찾을 수 없음. 예를 들어, 서버에 해당 리소스가 없거나, URL이 잘못되었을 때
5xx [Server Error]
서버의 문제로 오류가 발생한 경우로 재시도를 하면 서버의 복구 여부에 따라 성공할 수도 있음
5xx 오류는 서버 입장에서는 심각한 오류이기 때문에 실제로 서버의 오류가 있을 때만 발생시켜야 하며, 비즈니스 로직상의 오류를 절대 5xx로 처리하면 안됨
- 500 Internal Server Error: 서버에서 알 수 없는 오류가 발생하여 요청을 처리할 수 없는 일반적인 오류
- 502 Bad Gateway: 서버가 다른 서버로부터 잘못된 응답을 받았음. 이는 프록시나 게이트웨이 서버가 다른 서버로부터 유효하지 않은 응답을 받았을 때 발생
- 503 Service Unavailable: 서버가 일시적으로 과부하 상태이거나 유지 보수 중임을 나타냄
HTTP 헤더
Representation(표현) 관련 헤더
표현 데이터가 어떻게 이루어져 있고 어떤 방식으로 인코딩 및 디코딩 해야하는지 나타내는 메타 데이터같은 역할이다.
💡 여기서 말하는 Representation이란 HTTP 메세지의 본문을 말한다. 데이터베이스에 담긴 바이너리 리소스나 파일, 객체 정보 등을 HTML, JSON, XML 등으로 “표현”한다는 의미에서 이런 용어를 사용한다고 한다. (표준이 바뀌기 전에는 Entity라고 불렸음)
Content-Type
: 표현 데이터의 타입 (text/html; charset=UTF-8, application/json)Content-Encoding
: 표현 데이터의 인코딩 형식 (gzip, deflate)Content-Language
: 표현 데이터의 자연 언어(ko, en)Content-Length
: 표현 데이터의 길이
Content Negotiation(협상) 관련 헤더
클라이언트가 서버에게 요청한 리소스를 응답받을 때 선호하는 표현 방식이 있어, 혹시 서버가 그 방식으로 표현을 만들어 보내줄 수 있는지 물어보는 헤더다. 서버는 이를 고려해 표현을 최대한 맞춰 응답해 준다.
Accept
: 클라이언트가 선호하는 미디어 타입Accept-Charset
: 클라이언트가 선호하는 문자 인코딩Accept-Language
: 클라이언트가 선호하는 자연 언어Accept-Encoding
: 클라이언트가 선호하는 인코딩
협상 관련 헤더의 경우 클라이언트가 선호하는 방식이 서버에서 지원을 안 할 수도 있기 때문에 우선순위라는게 있다. 이를 위해 우선 순위 변수로 Quality Values(q)를 사용한다.
q
는 0~1 사이의 값을 가지며 클수록 높은 우선순위를 나타낸다. 만약 생략하면 값은 1이다.
- Accept-Language: ko,en;q=0.7
위 헤더의 경우 ko는 우선 순위 값이 1이고, en은 0.7을 가지므로 ko의 우선순위가 더 높다. 따라서 만약 서버가 ko와 en을 모두 지원한다면 Content-Language: ko
으로 표현을 응답하고, 만약 ko가 없다면 그 다음 우선순위인 en을 고려한다.
또한 구체적인 것이 우선순위가 높다. 예를 들어,
- Accept: text/*, text/plain
위 예시에서는 text/plain이 우선순위가 더 높다.
일반적인 정보 헤더
Referer
: 현재 요청된 웹 페이지의 이전 주소가 담겨있으며 요청 메세지에 담겨있음. 유입 경로를 분석할 때 주로 사용User-Agent
: 클라이언트의 어플리케이션 정보(웹 브라우저 정보 등). 어떤 브라우저에서 문제가 발생하는지 분석할 수 있음Server
: 요청을 처리하는 ORIGIN 서버의 소프트웨어 정보Date
: 메세지가 발생한 날짜와 시간
특별한 정보 헤더
Host
: 요청할 서버의 호스트 정보(도메인)가 담겨있으며 필수 값이다. 서버가 가상 호스트를 사용해 하나의 IP에 여러 호스트가 있을 수 있으므로 꼭 넣어줘야 한다.Location
: 응답코드 3xx에서 사용하는 리다이렉트 주소가 담겨 있음Allow
: 사용자가 지원하지 않는 HTTP 메서드로 요청했을 때 허용 가능한 HTTP 메서드를 알려줌
인증 헤더
Authorization
: 클라이언트의 인증 정보를 서버에 전달WWW-Authenticate
: 클라이언트의 요청이 인증 실패하여, 리소스 접근 시 필요한 인증 방법을 정의해 응답
Cookie(쿠키) 헤더
HTTP는 기본적으로 무상태(stateless) 프로토콜이므로, 서버는 각 요청 간의 클라이언트 상태를 기억하지 않는다. 쿠키는 이러한 상태를 유지하기 위한 대체 방법으로, 클라이언트의 브라우저에 저장 되었다가 이후 요청에서 서버로 다시 전송하게 됨으로써 웹 브라우저와 서버 간에 상태를 유지할 수 있게 된다.
Set-Cookie
: 서버가 클라이언트에게 쿠키를 설정하도록 지시하는 HTTP 응답 헤더. 이 정보는 클라이언트가 이후의 요청에 자동으로 서버에 전송하게 된다.Cookie
: 클라이언트가 서버에 요청을 보낼 때, 이전에 설정된 쿠키를 함께 전송하는 HTTP 요청 헤더.
주요 속성
<cookie-name>=<cookie-value>
: 쿠키의 이름과 값을 지정. 이름과 값은 문자열로 지정되며, 값은 URL 인코딩되어 전송- 예시: Set-Cookie: sessionId=abc123
Expires
: 쿠키의 만료 날짜를 지정. 이 속성을 통해 쿠키의 유효 기간을 설정할 수 있으며, 설정된 시간이 지나면 쿠키는 브라우저에서 자동으로 삭제- 예시: Set-Cookie: sessionId=abc123; Expires=Wed, 21 Aug 2024 07:28:00 GMT
Max-Age
: 쿠키의 유효 기간을 초 단위로 지정- 예시: Set-Cookie: sessionId=abc123; Max-Age=3600
Domain
: 쿠키가 유효한 도메인을 지정. 명시된 도메인의 서브 도메인까지 포함한다.- 예시: Set-Cookie: sessionId=abc123; Domain=example.com
Path
: 쿠키가 유효한 URL 경로를 지정합니다. 지정된 경로와 하위 경로에 대한 요청에서만 쿠키가 전송- 예시: Set-Cookie: sessionId=abc123; Path=/account
Secure
: 이 속성이 설정된 경우, 쿠키는 HTTPS 연결을 통해서만 전송- 예시: Set-Cookie: sessionId=abc123; Secure
HttpOnly
: 이 속성이 설정되면, 클라이언트 측 스크립트(JavaScript 등)에서 쿠키에 접근할 수 없음. 이를 통해 XSS(Cross-Site Scripting) 공격을 방지할 수 있다.- 예시: Set-Cookie: sessionId=abc123; HttpOnly
SameSite
: 이 속성은 CSRF(Cross-Site Request Forgery) 공격을 방지하는 데 사용
참고
'CS > Network' 카테고리의 다른 글
What is HTTP? (0) | 2024.07.21 |
---|---|
[네트워크] ARP (Address Resolution Protocol) (0) | 2023.03.26 |
[네트워크] OSI 7 계층 개요 (1) | 2023.03.26 |
[네트워크] 소켓 프로그래밍 개요 (0) | 2023.03.26 |
Network Layer (0) | 2019.05.26 |
- Total
- Today
- Yesterday
- Computer_Networking_A_Top-Down_Approach
- Thymeleaf
- 스프링 테스트
- 김영환
- 운영체제 반효경
- 생활코딩 javascript
- git branch
- Python Cookbook
- jsp
- 파이썬 for Beginner 연습문제
- Spring Data JPA
- Spring Boot
- git merge
- JPA
- spring mvc
- 스프링 컨테이너
- shell code
- 방명록 프로젝트
- git
- 파이썬 for Beginner 솔루션
- 패킷 스위칭
- Spring
- 지옥에서 온 git
- 스프링
- Gradle
- 쉽게 배우는 운영체제
- 쉘 코드
- 선형 회귀
- 프로그래머스
- Do it! 정직하게 코딩하며 배우는 딥러닝 입문
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |