July 03, 2021
IP (인터넷 프로토콜)의 역할
IP 패킷 정보
IP 프로토콜의 한계
비연결성
비신뢰성
프로그램 구분
TCP
인터넷 프로토콜 스택의 4계층
TCP/IP를 이용한 데이터 전달 방식
TCP/IP 패킷 정보
TCP 특징
연결 지향 - TCP 3 way handshake (가상 연결)
데이터 전달 보증
순서 보장
PORT
PORT 번호 범위
0 ~ 1023 : 잘 알려진 포트, 사용하지 않는 것이 좋음
IP의 문제점
DNS로 해결
DNS를 사용한 통신
URI (Uniform Resource Identifier)
URL (Uniform Resource Locator)
foo://example.com:8080/over/there?name=jessie#nose
와 같은 형태URN (Uniform Resource Name)
urn:example:person:jessie:nose
와 같은 형태URL 분석 example
scheme://[userinfo@]host[:port][/path][?query][#fragment]
https://www.google.com/search?q=hello&hl=ko
https
: protocolwww.google.com
: host name443
: port number/search
: pathq=hello&hl=ko
: query parameterURL scheme
URL userinfo@
URL host
URL port
URL path
/members/100
, /items/iphone2
URL query
?keyA=value&keyB=valueB
URL fragment
웹 브라우저가 HTTP 요청 메세지 생성
GET /search?q=hello&hl=ko HTTP/1.1 Host:www.google.com
서버에서는 요청 패킷 정보가 도착하면 HTTP 메세지를 가지고 해석한 후 데이터를 찾고 응답 메세지를 생성
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 3423
<html>
<body>...</body>
</html>
HTTP란
HTTP 역사
HTTP/1.1 (1997) : 가장 많이 사용, 우리에게 가장 중요한 버전
HTTP/2 (2015) : 성능 개선
기반 프로토콜
HTTP 특징
클라이언트 서버 구조
Stateless (무상태 프로토콜)
Stateful (상태 유지)
Stateful / Stateless 차이를 보여주는 example
Stateful - example 1 (동일한 점원)
// 첫 번째 요청
- 고객: 이 노트북 얼마인가요?
- 점원A : 100만원입니다
// 두 번째 요청
- 고객: 2개 구매할게요
- 점원A : 200만원입니다.
점원A는 고객의 이전 상태를 유지하고 있기 때문에 두 번째 요청에서 고객이 어떤 걸 구매하겠다고 말하지 않았는데도 점원A는 노트북 2개로 이해하고 계산한다.
Stateful - example2 (요청마다 점원이 달라진 경우)
// 첫 번째 요청
- 고객: 이 노트북 얼마인가요?
- 점원A : 100만원입니다
// 두 번째 요청
- 고객: 2개 구매할게요
- 점원B : ? 무엇을 2개 구매하시겠어요?
점원B는 고객이 어떤 걸 구매하려고 하는지 알 수 없기 때문에 장애가 발생한다.
Stateless
// 첫 번째 요청
- 고객: 이 노트북 얼마인가요?
- 점원A : 100만원입니다
// 두 번째 요청
- 고객: 노트북 2개 구매할게요
- 점원B : 200만원입니다.
무상태에서는 고객이 요청마다 필요한 데이터를 다 전달하기 때문에 요청마다 동일한 점원이든 점원이 달라지든 상관없다.
Stateless의 실무 한계
무상태
상태 유지
TCP/IP 연결을 유지하는 모델의 단점
TCP/IP 연결을 유지하지 않는 모델
비 연결성 소개
1시간 동안 수천 명이 서비스를 사용해도 실제 서버에서 동시에 처리하는 요청은 수십개 이하로 매우 작음
비 연결성의 한계와 극복
지금은 HTTP 지속 연결(Persistent Connections)로 문제 해결
나쁜 API URI 설계 Example - 회원 정보 관리 API
/read-member-list
/read-member-by-id
/craete-member
/update-member
/delete-member
API URI 설계에서 가장 중요한 것은 리소스 식별!
좋은 API URI 설계 Example - 회원 정보 관리 API
/members
/members/{id}
/members/{id}
/members/{id}
/members/{id}
member
→ members
)리소스와 행위를 분리하자
리소스와 해당 리소스를 대상으로 하는 행위를 분리
HTTP 메서드란?
주로 사용되는 HTTP 메서드
GET
: 리소스 조회POST
: 요청 데이터 처리, 주로 등록에 사용PUT
: 리소스를 대체, 해당 리소스가 없으면 생성PATCH
: 리소스 부분 변경DELETE
: 리소스 삭제기타 HTTP 메서드
HEAD
: GET 과 동일하지만 메세지 부분을 제외하고 상태 줄과 헤더만 반환OPTIONS
: 대상 리소스에 대한 통신 가능 옵션(메서드)을 설명 (주로 CORS에서 사용)CONNECT
: 대상 자원으로 식별되는 서버에 대한 터널을 설정TRACE
: 대상 리소스에 대한 경로를 따라 메세지 루프백 테스트를 수행GET
POST
주로 전달된 데이터로 신규 리소스 등록 or 요청 데이터 처리에 사용한다.
신규 리소스 등록
요청 데이터 처리
다른 메서드로 처리하기 애매한 경우
PUT
리소스를 대체
주의! PUT은 리소스를 완전히 대체한다
PUT /members/100
에 Request Body로 { "age": 50 }
를 전송하면 서버에 { "name": "Jessie", "age": 20 }
으로 있었더라도 name
필드가 삭제되고 { "age": 50 }
로 대체 된다.PATCH
DELETE
HTTP 메서드 | 요청에 Body 존재 | 응답에 Body 존재 | 안전 | 멱등 | 캐시 가능 |
---|---|---|---|---|---|
GET | X | O | O | O | O |
HEAD | X | X | O | O | O |
POST | O | O | X | X | O |
PUT | O | O | X | O | X |
DELETE | X | O | X | O | X |
CONNECT | O | O | X | X | X |
OPTIONS | 선택사항 | O | O | O | X |
TRACE | X | O | O | O | X |
PATCH | O | O | X | X | O |
안전
멱등
캐시 가능
실제로는 GET, HEAD 정도만 캐시로 사용
Client → Server 데이터 전달 방식
Query Parameter
Message Body
Client → Server 데이터 전송하는 4가지 상황
정적 데이터 조회
GET /static/star.jpg
동적 데이터 조회
GET /search?q=hello&hl=ko
HTML Form을 통한 데이터 전송
ex)
<form action="/save" method="post">
<input type="text" name="username" />
<input type="text" name="age" />
<button type="submit">전송</button>
</form>
form submit 버튼을 누르면 웹 브라우저가 아래와 같은 http 메세지를 생성해준다.
POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded
username=kim&age=20
HTTP API를 통한 데이터 전송
서버 to 서버
앱 클라이언트
웹 클라이언트
HTTP API 컬렉션
ex) 회원 관리 API 제공
/members
→ GET/members
→ POST/members/{id}
→ GET회원 수정 /members/{id}
→ PATCH, PUT, POST
/members/{id}
→ DELETEHTTP API - 스토어
HTML FORM 사용
컨트롤 URI
/new
, /edit
, /delete
와 같은 방식이 컨트롤 URI문서(document)
/members/100
, /files/star.jpg
컬렉션(collection)
/members
스토어(store)
files
컨트롤러(controller), 컨트롤 URI
/members/{id}/delete
상태코드란
상태코드 종류
요청 정상 처리
200 OK
201 Created
Location
헤더 필드로 식별202 Accepted
204 No Content
요청을 완료하기 위해 유저 에이전트(웹 브라우저)의 추가 조치 필요
리다이렉션의 이해
Location
헤더가 있으면, Location
위치로 자동 이동(리다이렉트)example
/event
접근GET /event
요청301 Moved Permanently Location: /new-event
응답/new-event
로 리다이렉트GET /new-event
요청200 OK
응답리다이렉션의 종류
영구 리다이렉션 - 특정 리소스의 URI가 영구적으로 이동됨
일시 리다이렉션 - 일시적인 변경
특수 리다이렉션
301 Moved Permanently
302 Found
303 See Other
304 Not Modified
307 Temporary Redirect
308 Permanent Redirect
400 Bad Request
401 Unauthorized
WWW-Authenticate
헤더와 함께 인증 방법을 설명참고
403 Forbidden
404 Not Found
500 Internal Server Error
503 Service Unavailable
Retry-After
헤더 필드로 얼마 뒤에 복구되는 지 보낼 수 있음HTTP 헤더 용도
helloworld: hihi
)HTTP BODY
Content-Type
example
Content-Encoding
example
Content-Language
example
Content-Length
Accept
: 클라이언트가 선호하는 미디어 타입 전달Accept-Charset
: 클라이언트가 선호하는 문자 인코딩Accept-Encoding
: 클라이언트가 선호하는 압축 인코딩Accept-Language
: 클라이언트가 선호하는 자연 언어협상과 우선순위1
ex) Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
ko-KR;q=1
(q 생략 가능)ko;q=0.9
en-US;q=0.8
en;q=0.7
협상과 우선순위2
ex) Accept: text/*, text/plain, text/plain;format=flowed, */*
text/plain;format=flowed
text/plain
text/*
*/*
단순 전송
Content-Length
를 알고 있을 때 사용 가능압축 전송
Content-Encoding
을 추가해줘야 한다.분할 전송
Transfer-Encoding
을 추가해줘야 한다.Content-Length
를 넣으면 안된다.범위 전송
Form
Referer
A
→ B
로 이동하는 경우, B
를 요청할 때 Referer: A
를 포함해서 요청함Referer
를 사용해서 유입 경로 분석 가능User-Agent
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 *KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36
Server
Server: Apache/2.2.22 (Debian)
Date
Date: Tue, 15 Nov 1994 08:12:41 GMT
Host
ex)
GET /search?q=hello&hl=ko HTTP/1.1
Host: www.google.com
Location
3xx
응답 결과에 Location
헤더가 있으면 Location
위치로 자동 이동(리다이렉트)201 (Created)
: Location
값은 요청에 의해 생성된 리소스 URI3xx (Redirection)
: Location
값은 요청을 자동으로 리디렉션 하기 위한 대상 리소스를 가리킴Allow
405 (Method Not Allowed)
에서 응답에 포함해야 함Allow: GET, HEAD, PUT
와 같이 응답 헤더에 포함된다.Retry-After
503 (Service Unavailable)
: 서비스가 언제까지 불능인지 알려줄 수 있음Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
(날짜 표기)Retry-After: 120
(초 단위 표기)Authorization
: 클라이언트 인증 정보를 서버에 전달WWW-Authenticate
WWW-Authenticate: Newauth realm="apps", type=1, title="Login to \"apps\"", Basic realm="simple"
Set-Cookie
: 서버에서 클라이언트로 쿠키 전달(응답)Cookie
: 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청시 서버로 전달쿠키 미사용 example
GET /welcome HTTP/1.1
요청HTTP/1.1 200 OK 안녕하세요 손님
응답 (로그인을 하더라도 Stateless 하기 때문에 누군지 몰라서 “손님”으로 응답함)
Stateless
쿠키 미사용한 대안 - 모든 요청에 사용자 정보 포함
example
GET /welcome?user=홍길동 HTTP/1.1
요청HTTP/1.1 200 OK 안녕하세요 홍길동님
응답쿠키 사용한 대안
example
POST /login HTTP/1.1 user=홍길동
요청HTTP/1.1 200 OK Set-Cookie: user=홍길동
응답user=홍길동
저장GET /welcome HTTP/1.1 Cookie: user=홍길동
요청HTTP/1.1 200 OK 안녕하세요 홍길동님
응답Cookie
헤더를 만들어서 서버 요청 때 함께 보낸다.쿠키
ex) set-cookie: sessionId=abcde1234; expires=Sat, 26-Dec-2020 00:00:00 GMT; path=/; domain=.google.com; Secure
sessionId
: 세선 idexpires
: 만료일시path
: 쿠키 허용 패스domain
: 쿠키 허용 도메인사용처
쿠키 정보는 항상 서버에 전송됨
localStorage
, sessionStorage
)참고주의!
쿠키 - 도메인 지정
domain=example.org
도메인을 명시할 경우, 명시한 문서 기준 도메인 + 서브 도메인 포함
domain=example.org
를 지정해서 쿠키 생성
example.org
, dev.example.org
, … 에서 쿠키 접근 가능도메인 지정을 생략할 경우, 현재 문서 기준 도메인만 적용됨
example.org
에서 쿠키를 생성하고 domain 지정을 생략
example.org
에서만 쿠키 접근 가능쿠키 - 경로 지정
path=/
와 같이 루트로 지정함ex) path=/home
지정
/home
, /home/level1
, /home/level2
가능/list
불가능쿠키 - 보안
쿠키는 원래 http, https를 구분하지 않고 전송함
Secure
HttpOnly
document.cookie
)SameSite
캐시가 없을 때
example
첫 번째 요청
두 번째 요청
캐시 적용
example
첫 번째 요청
서버에서 1.1M 크기 응답
HTTP/1.1 200 OK
Content-Type: image/jpeg
**cache-control: max-age=60**
Content-Length: 34012
cache-control
: 캐시가 유효한 시간(초)두 번째 요청
세 번째 요청 (캐시 유효 시간 초과)
응답 결과를 브라우저 캐시에 기존 데이터를 지우고 저장한다.
→ 기존 브라우저 캐시에 저장된 (유효시간 만료된) 데이터와 새로 받아온 데이터가 동일한데 새로 받아올 필요가 있을까? → 검증 헤더와 조건부 요청으로 해결
검증 헤더
조건부 요청 헤더
캐시 시간 초과 : 캐시 유효시간이 초과해서 서버에 다시 요청하면 다음 두 가지 중 한 가지 상황이 나타난다.
서버에서 기존 데이터를 변경하지 않음
Last-Modified / If-Modified-Since 방식으로 해결
과정 example
Last-Modifed
응답 헤더 추가 (검증 헤더)Last-Modifed
를 브라우저 캐시에 응답 결과, 유효 시간과 함께 저장if-modified-since
(조건부 요청) 추가 (브라우저 캐시에서 Last-Modifed
값을 가져올 수 있다.)if-modified-since
값과 서버에 가지고 있는 데이터의 Last-Modifed
값을 비교해서 똑같으면 → 데이터가 수정되지 않았음을 검증할 수 있다.304 Not Modified
를 보낸다. (HTTP Body 없음)정리
단점
서버에서 별도의 캐시 로직을 관리하고 싶은 경우
ETag / If-None-Match 방식으로 해결
캐시용 데이터에 임의의 고유한 버전의 이름을 달아둠
데이터가 변경되면 이 이름을 바꿔서 변경함 (Hash 다시 생성)
ex)
캐시 제어 헤더
Cache-Control
: 캐시 제어
Cache-Control: max-age
: 캐시 유효 시간, 초 단위Cache-Control: no-cache
: 데이터는 캐시해도 되지만, 항상 origin 서버에 검증하고 사용Cache-Control: no-store
: 데이터에 민감한 정보가 있으므로 저장하면 안됨. 메모리에서 사용하고 최대한 빨리 삭제Pragma
: 캐시 제어 (하위 호환)
Paragma: no-cache
Expires
: 캐시 유효 기간 (하위 호환)
Cache-Control: max-age
권장Cache-Control: max-age
와 함께 사용하면 Expires
는 무시검증 헤더
조건부 요청 헤더
example
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache