Http 기본 지식
Stateful, Stateless
서버가 클라이언트의 상태를 유지하느냐(Stateful) vs 유지하지 않느냐(Stateless)
Stateful 서버일 경우일때는, 서버가 변경되기 까다롭고 클라이언트의 상태를 가지고 있는 서버의 장애가 날시에 대처가 쉽지 않다.
HTTP는 Stateless, 클라이언트의 상태를 유지하지 않음 -> 서버를 쉽게 바꿀수 있다 -> 서버의 확장성이 용이 하다(Scale Out)
단점: 로그인이 필요없는 화면은 유리하지만, 클라이언트의 로그인 상태를 유지해야하는데 추가적인 것이 필요. 보낼때마다 문맥(Context)이 없이 때문에 데이터 전송량이 많아질수 있다.(중복 전송/응답)
HTTP = Stateless 특성을 잘 활용하여 API를 구성하는 것이 매우 중요.
비 연결성
필요하지 않을 때는 연결을 유지하지 않음 최소한의 자원을 사용하여 효율적으로 서버를 운영할수 있음.
단점: 연결할 때마다 TCP/IP 연결을 맺어야함 -> 3 Way Handshake 시간 비효율 웹브라우저를 통해 요청하면, HTML, JS, CSS, 이미지 등 다운로드
극복: HTTP 지속 연결(Persistent Connections) 한번 요청하면 어느정도 시간 까지는 연결을 지속하여 Connection(HandShake)을 최소화 HTTP/2, /3에서 최적화하여 성능 극대화 노력
HTTP 메시지
start-line: method SP(공백) request-target HTTP-Version
*( header-field): field-name: value
CRLF
[Message-Body]
HTTP Method
API URI 고민
리소스라는 것이 무엇인지 구분필요함 URI는 리소스만 식별한다. 리소스와 리소스를 대상으로 하는 행위를 분리 EX)
- 리소스: 회원
- 행위: 조회, 등록, 삭제, 변경
GET
body로 메시지 전달 가능하지만 지원하지 않는 시스템이 있고 실무에서 사용하지 않음
POST
메시지 바디를 통해 서버로 요청 데이터 전달 주로 신규 데이터를 등록하는 용도로 사용
- 응답시 Location 헤더 사용하여 리소스 위치 반환
- 생성된 데이터를 body로 반환 리소스 생성, 요청데이터 처리(리소스와 관련된 데이터 처리가 일어나는 경우) - POST /orders/{orderId}/start-delivery(컨트롤 URI) 다른 메서드로 처리하기 애매한 경우에도 POST를 사용
PUT
리소스를 대체
- 리소스가 있으면 대체(부분 업데이트 불가)
- 리소스가 없으면 생성 POST와의 차이점: 클라이언트가 리소스의 위치를 알고 URI 지정
PATCH
리소스를 부분 변경
DELETE
리소스 삭제
HTTP Method 속성
안전(Safe)
GET, HEAD, OPTIONS, TRACE
멱등(Idempotent)
한 번 호출하든 두번호출하든 100번호출하든 결과가 똑같다. GET, PUT, DELETE 왜 필요한가? 자동복구 메커니즘: 서버가 TIMEOUT등으로 정상 응답을 못주었을때, 클라이언트가 같은 요청을 다시 할수 있는가에 대한 판단 근거
캐시가능(Cacheable)
응답 결과 리소스를 캐시해서 사용해도 되나? GET, HEAD, POST, PATCH 캐시 가능 실제로는 GET, HEAD 정도만 캐시 사용
- POST, PATCH는 본문 내용까지 캐시 키로 고려해야하는데 구현이 쉽지 않음
클라이언트에서 서버로 데이터 전송
정적 데이터 조회
- 이미지, 정적 텍스트 문서, 조회는 GET 사용
동적 데이터 조회
- 쿼리 파라미터 사용, 주로 검색, 게시판 목록에서 정렬 필터(검색어)
HTML Form 데이터 전송(GET, POST만 지원)
- POST인 경우에는 자동으로 브라우저가 body parameter만들어 전송
- GET인 경우에는 자동으로 브라우저가 query parameter로 만들어 전송
HTTP API 데이터 전송
- 서버 TO 서버
- 앱 클라이언트
- 웹 클라이언트
- POST, PUT, PATCH 모두 사용가능
- Content-Type: application/json을 주로 사용
HTTP API 설계 예시
설계 원칙: 리소스를 중심으로 설계한다.
POST: 신규 자원 등록(회원 가입의 경우)
- 클라이언트는 등록될 리소스의 URI를 모르고 데이터만 전달한다. 서버가 URI를 생성하고 클라이언트에게 알려준다.
PUT: 신규 자원 등록(파일 등록의 경우)
- 파일 등록시 클라이언트가 URI(filename)을 알고 있기 때문에 신규 자원등록 시에 PUT을 사용할 수 있다.
신규 데이터 등록 시에 클라이언트가 URI를 알고 있느냐 여부에 따라서 POST와 PUT을 구분하여 사용한다. PUT을 사용하는 경우에 대해서 Store라고 한다. 클라이언트가 URI를 알고 관리한다.
Controll URI는 최대한 지양하지만, 메소드 제한(HTML Form)이 있는 경우에는 사용할 수도 있다. 하지만 리소스를 중심으로 설계하는 것을 지향하며, 동사 단어를 사용하는 스타일로 설계한다.
URI 설계 개념
- restfulapi.net/resource-naming
문서
- 단일 개념(파일 하나, 객체 인스턴스, 데이터베이스 row)
컬렉션
- 서버가 관리하는 리소스 디렉터리
스토어
- 클라이언트가 관리하는 자원 저장소
컨트롤러, 컨트롤 URI
- 문서, 컬렉션, 스토어로 해결하기 어려운 추가 프로세스 사용, 동사 단어 사용
- ex) POST /members/{id]}/delete
HTTP 상태 코드
1XX
- 거의 사용하지 않음. 요청이 수신되어 처리중.
2XX
- 200 OK: 요청 성공
- 201 Created: 생성됨.
- 202 Accepted: 요청이 접수되었으나 처리가 완료되지 않았음
- 204: 서버가 요청을 성공적으로 수행했지만, 응답 페이로드 본문에 보낼 데이터가 없음
3XX
웹 브라우저는 3XX 응답에 Location 헤더가 있으면, Location 위치로 자동 이동(리다이렉트)한다.
- 300 Multiple Choices: 안씀.
- 301 Moved Permanently: 영구 리다이렉션, 일시 리다이렉션, 특수 리다이렉션
영구 리다이렉션
- 리소스의 URI가 영구적으로 이동
- 원래의URL을 사용하지 않고
- 301: POST요청시 리다이렉트되는 URI로 GET요청으로 변경됨. body가 제거되어버릴수도 있음.
- 308: POST요청시 body와 함께 그대로 POST 요청하게됨(301의 해결버전. 최초 스펙은 308이 301이였으나 브라우저 구현이 301의 형태로 되어, 308을 새로 만듬)
일시적인 리다이렉션
- URI가 일시적으로 변경
- 검색 엔진 등에서 URL을 변경하면 안됨.
- 302 Found: 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음.
- 307 Temporary Redirect: 032와 기능 동일, 리다이렉트시 요청 메서드와 본문 유지(메서드 변경되지 않음)
- 303 See Other: 302와 기능 동일, 리다이렉트시 요청 메서드가 GET으로 변경
일시적인 리다이렉션 예시
- PRG(POST, Redirect, GET): 커머스에서 주문 요청에 대한 API라고 가정하였을때, POST 주문요청을 한 후에 200 OK 처리 시에 새로고침을 하게 되면 동일 POST 주문요청이 동일하게 요청 된다. 그래서 POST 처리 후에 302 혹은 303으로 Redirection 처리(Location 헤더)하여 주문 완료 화면 GET 으로 이동 시키면 해당 문제를 해결할수 있음.
기타 리다이렉션
- 304 Not Modified: 캐시를 목적으로 사용. 클라이언트에게 리소스가 수정되지 않았음을 알려준다. 따라서 클라이언트는 로컬 PC에 저장된 캐시를 재사용ㅎ나다. (캐시로 리다이렉트 한다.) 304 응답은 응답에 메시지 바디를 포함하면 안된다.(로컬 캐시를 사용해야 하므로)
4XX
- 클라이언트의 요청에 잘못된 문법등으로 서버가 요청을 수행할 수 없음
- 오류의 원인이 클라이언트에 있음.
- 400 Bad Request: 클라이언트가 잘못된 요청을 해서 서버가 요청을 처리할 수 없음.
- 401 Unauthorized: 클라이언트가 해당 리소스에 대한 인증이 필요함. (인증이 되지 않았지만 인가되지 않음으로 메시지. 스펙에 정의되어 잇음)
- 403 Forbidden: 인가되지 않았음.
- 404 Not Found: 요청 리소스를 찾을 수 없음
5XX
- 오류의 원인이 서버에 있음.
- 500 Internal Server Error: 서버 문제로 오류 발생. 애매하면 500
- 503 Service Unavailable: 서비스 이용 불가(Retry-After 헤더 필드로 얼마뒤에 복구되는지 참고 가능)
HTTP 헤더
표현(representation) 헤더
- 표현 헤더(content-type, content-length, content-encoding, content-language): RFC7230
- request, response 둘다 사용
협상(content negotiation)
- 클라이언트가 요청하는 형태의 표현 요청
- Accept: 클라이언트가 선호하는 미디어 타입 전달
- Accept-Language: 클라이언트가 선호하는 자연 언어
- Accept-Charset: 클라이언트가 선호하는 문자 인코딩
- Accept-Encoding: 클라이언트가 선호하는 압축 인코딩
협상과 우선순위1
- Quality Values(q)값 사용, 0~1 클수록 높은 우선순위
- Accept-Language: ko;q=0.9,en;q=0.7
협상과 우선순위2
- 구체적인것이 우선한다.
- Accept: text/,text/plain,text/plain;format=flowed,/*
- 우선순위: text/plain;format=flowed,text/plain,text/,/*
협상과 우선순위
- 구체적인 것을 기준으로 미디어 타입을 맞춘다.
전송방식
단순 전송
- Content-Length 헤더 필수
압축 전송
- Content-Encoding 헤더 필수
분할 전송
- Transfet-Encoding: chunked 헤더 필수, Content-Length 넣지 않음. 예상 불가한 상태
범위 전송
- Range, Content-Range: 큰 이미지 등을 전송 시에 부분 범위로 나누어서 전송
일반 정보
- From: 유저 에이전트의 이메일 정보
- Referer: 현재 요청된 페[이지의 이전 웹 페이지 주소(유입 경로 분석 가능)
- User-Agent: 블라이언트의 애플리케이션 정보(웹라우저 정보). 어떤 종류의 브라우저에서 장애가 발생하는지 파악 가능, 통계 정보
- Server: 요청을 처리하는 ORIGIN 서버(중간 경로의 서버가 아닌 표현 데이터를 생성해주는 서버)의 소프트웨어 정보
- Date: 메시지가 발생한 날짜와 시간.
특별한 정보
- Host: 요청한 호스트의 정보(도메인). 필수값. 하나의 IP에 여러개의 도메인이 할당되어 있을 수 있음.
- Location: 페이지 리다이렉션. 3XX 응답의 결과에 Location 헤더가 있으면 자도 ㅇ이동 201 Created: Location 값은 요청에 의해 생성된 리소스의 위치
- Allow: 허용 가능한 HTTP 메서드
- Retry-After: 503 서비스가 언제까지 불능인지 알려줄 수 있음.(날짜 표기 or 초단위표기)
인증
- Authorization: 클라이언트 인증 정보를 서버에 전달
- WWW-Authorization: 리소스 접근시 필요한 인증 방법 정의. 401 Unathorization 응답시에 표시 해주어야함.
쿠키
캐시, 조건부 헤더
캐시 기본 동작
- 캐시 미적용: 요청마다 헤더와 바디를 응답한다.
- 캐시 적용: cache-control 헤더 사용(캐시 유효 시간)하고, 기간 내에는 로컬에 저장된 데이터를 사용한다.
- 다만, 만료될 때마다 다운로드 하게 된다.
검증헤더와 조건부 요청1
Last-Modified, if-modified-since
- Last-Modified 헤더 사용(서버가 응답시에 cache-control과 함께)
- 이후 클라이언트가 if-modified-since 헤더(Last-Modified로 받은 값)를 이용해서 서버에 요청
- 서버에서 if-modified-since를 보고 304(Not Modified + No Body), 변경된 데이터로 응답할 지 결정 가능하다.
- 최소 단위가 초단위,
검증헤더와 조건부 요청2
Etag(Entity Tag), If-None-Match
- 서버에서 응답한 Etag 헤더값과 함께 캐시 저장하고, 동일 리소스 요청 시에 If-None-Match에 Etag값을 요청하여 다르면 변경된 리소스 응답, 동일하면 304로 응답
캐시와 조건부 요청 헤더
Cache-Control
- max-age: 초단위 만료값.
- no-cache: 데이터는 캐시해도 되지만, 항상 원서버(ORIGIN)에 검증하고 사용.
- no-store: 데이터에 민감한 정보가 있으므로 저장하면 안됨.
Pragma: 하위 호환
Expires: 캐시 만료일을 정확한 날짜로 지정
프록시 캐시
Origin 서버: 리소스를 관리하고 제공하는 서버
프록시 캐시 서버: CDN, Cloud Front
- Cache-Control: public(CDN에 저장 가능)
- Cache-Control: private (로컬 저장 가능)
- Cache-Control: s-maxage(프록시 캐시에만 적용되는 max-age)
- Cache-Control: Age (HTTP 헤더). 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)
캐시 무효화
- 확실한 캐시 무효화 응답
- Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
no-cache: 캐시 해도 되지만 사용전 서버에 검증 필수
- no-store: 민감한 정보가 있어서 저장하면 안됨.
- must-revalidate: 캐시 만료후 최초 조회시 원서버 조회 필요. 원서버에 조회가 불가한 경우가 있으면 504 Gateway Timeout 발생 시켜야함.