모든 개발자를 위한 HTTP 웹 기본 지식

·2023년 7월 2일

인프런 HTTP 강의

목록 보기
1/1
post-thumbnail

프로젝트를 진행하다 부족해보이는 부분이 넘 만항서..ㅠㅠ
김영환님 강의를 얼레벌레 다 들었고요.. 정리라도 합시다

IP(Internet Protocol)

저는 sohyun이고, 미국에 살고있습니다. 전주에 살고있는 박머머리에게 새우 사진을 지금 당장 한장 보내고싶을 때, 어떻게 보내야할까요?

비둘기 다리에 묶어서 보내면 너무 오래걸리고, 중간에 죽을 수도 있고, 비둘기가 도착했더라도 도착했을 당시 박머머리가 여행을 떠났을 수도 잇습니다 sohyun은 이 사실을 당연히 모를거구여. 헉..~ 불안정하다!
우리는 다행히도 2023년에 살고 있어서, 인터넷이라는걸 이용하면 됩니다.

비둘기와 소현, 박머머리를 인터넷에 비유해본다면
제가 보내고싶은 새우 사진은 보낼 데이터고, 비둘기는 패킷(통신 단위, package + bucket), 전주, 미국은 지정한 주소(IP Address), 보내는 당사자인 소현은 클라이언트, 박머머리는 서버입니다.

앞에서 말했듯, 단순 IP통신은 비둘기 전달법의 위험성을 모두 갖고잇슴다.
비둘기가 산에도 갔다가 화장실도 갓다가 러시아도 갓다가 할거 다하고 온다면(노드를 효율적으로 타지 못했다면) 속도가 저하되고,
가다가 죽어버릴 수도 있고(패킷, 데이터 유실)
도착했더라도 박머머리가 없을 수도 있습니다 sohyun은 그거에 대해서 알빠노 난 이미 줫음이라고 할거구여(서버 다운, 결과값 클라이언트가 확인 못함)

만일! 제대로 도착했다면? 박머머리는 반드시 답장을 써야만합니다.
목적지 IP Address를 향해서 가는 패킷은 데이터를 감싸고 있는 둘기입니다.
둘기 다리에는 새우 사진(데이터)이 묶여있고, 패킷인 둘기 이마빡에는 출발지IP, 목적지 IP, 기타 정보를 인두로 지져놨읍니다. 정상적으로 도달을 했다면 그 과정에서 둘기는 자기만의 경로(노드)로 전주로 향햇다는거고(클라이언트로→서버 패킷 전달), 박머머리가 정상적으로 패킷을 전달 받아서, 그걸 까보고 아 새우 귀여워~ 라는 답장을 쓴다면(서버→클라이언트 패킷 전달) 돌아갈 때의 둘기는 이전의 경로를 인지하고 효율적인 루트를 타서 미국으로 돌아옵니다

정리하자면

IP 프로토콜의 한계

  • 비연결성
    • 패킷을 받을 대상이 없거나, 서비스 불능 상태여도 패킷을 전송합니다.(알빠노 난 전달했다)
  • 비신뢰성
    • 중간에 패킷이 사라지면?(둘기의 세계여행 or 죽음)
    • 패킷이 순서대로 안오면?(’안녕하세요?’를 2시에 보내고, ‘이 편지는 영국에서부터…’를 4시에 보냈는데 4시에 보낸걸 먼저 받는다면?)
  • 프로그램 구분
    • 같은 IP를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상이면?

이런 위험성들을 보완하기 위해 나온게 바로바로~~

프로토콜 계층

  • 클라이언트에서 서버로 데이터를 전송할 때 거치는 과정들로, 위쪽 계층부터 아래로 내려오면서 패킷을 하나씩 더 겉에 감싸는 방식.
  1. IP 계층
    1. 출발지 ip, 목적지 ip 등..
  2. TCP/IP 패킷
    1. 출발지 port, 목적지 port, 전송 제어, 순서, 검증 정보..
    2. TCP(Transmission Control Protocol)
      1. 연결 지향 - TCP 3 way handshake(가상 연결)
        1. 논리적 연결로, 서버 - 클라이언트를 먼저 연결하고, 메세지를 보냄
        2. 클→서 SYN(접속 요청), 서 → 클SYN+ACK(요청 수락), 클 → 서 ACK 순서
        3. 이후에 데이터 전송을 통해 양측 신뢰 가능한 상태를 보장받음.
      2. 데이터 전달 보증
        1. 서버가 데이터를 받았는지 못받았는지 클라이언트가 결과를 알 수있다.
      3. 순서 보장
        1. 패킷1, 패킷2, 패킷3 순서로 보냈을 때 서버는 패킷1, 패킷3, 패킷2 순서로 도착했다면 서버는 순서가 꼬인 부분들을 다 버리고, 패킷 2부터 다시 보내라고 요청.
      4. 결론적으로 이는 신뢰할 수 있는 프로토콜로, 대부분 사용하고있음.
    3. UDP(User Datagram Protocol)
      1. 하얀 도화지(거의 기능 없..)
      2. 연결지향 아님.
      3. 데이터 전달 보증하지 못한다.
      4. 순서도 보장 못한다.
      5. 단순하고 빠르다
      6. IP와 거의 같지만, PORT, 체크섬 정도만 추가됨.
        1. PORT?
          1. 하나의 IP에서 여러 어플리케이션으로부터 들어오는 패킷을 구분해준다.
      7. 애플리케이션에서 추가적 최적화 등의 행위가 가능하다.

IP 패킷과 TCP 세그먼트를 결정짓는 차이점은 PORT이다.

IP 패킷은 출발지, 목적지 IP. 즉 큰 틀의 서버만 지니고 있지만 TCP 세그먼트가 지니고 있는 PORT의 경우 서버 내부에서 돌아가는 애플리케이션 목적지를 알 수 있도록 한다.
같은 IP 내에서 프로세스를 구분해준다는 소리다.

DNS(Domain Name System)

  • IP는 매번 긴 자리수를 기억하기 어렵고, 변경될 수 있다.
  • 도메인명은 수정하지 않는 한 임의로 변경되지 않음.
  • 클라이언트에서 서버로 통신을 시도할 때, DNS를 먼저 찾음.
  • ip 변경 시 DNS의 ip 수정하면 된다. 전화번호부

URI(Uniform Resource identifier)

  • locator(위치), name(resource 이름 그 자체) 혹은 둘 다 추가로 분류 가능.
  • locator는 변할 수 있지만, name은 변하지 않음. 하지만 이름만으로 실제 리소스를 찾을 수 있는 방법이 보편화되지 않음.

  • scheme : 어떤 방식으로 자원에 접근할 것인가 (클라 - 서버간)의 약속 규칙
    • http -> 80포트, https -> 443포트. 포트는생략 가능.
  • Userinfo : 유저 정보를 넣어서 보낼 수 있찌만, 거의 안함
  • host : 도메인명 혹은 IP주소 직접 사용
  • Port : 접속 포트. 일반적으로 생략. 생략시 http 80, https 443
  • Path : 리소스 경로(path), 계층적 구조
    • /home/file1.jpg
    • /members
    • /members/100, /items/iphone12
  • query
    • Key=value 형태
    • ?로 시작, &로 조건 추가
      • ?keyA=valueA&keyB=valueB
    • 쿼리 파라미터, 쿼리 스트링. 모두 문자 형태로 넘어가며, 웹서버에 제공하는 파라미터, 문자 형태
  • fragment : html 내부 북마크 등에 사용하며, 전송 정보 아님.

host명(dns 조회 -> 아이피 얻어냄)과 port를 조합해 http 요청 메시지를 작성한다.

HTTP 요청 메시지

  • GET /search?q=hello&hl=ko HTTP/1.1
  • Host:www.google.com
      1. 웹 브라우저가 위와 같은 http메시지생성
      1. socket라이브러리를 통해 전달
      • A:TCP/IP연결(IP, PORT)
      • B:데이터 전달
      1. TCP/IP패킷생성, HTTP메시지 포함.

https://www.google.com/search?q=hello&hl=ko라는 urI에 들어갔을 때 어떤 작용이 있는지..

TCP/IP 패킷은 까서 버리고, HTTP 메시지를 해석해서 응답 메시지를 보낸다.

이 응답 메세지를 받은 클라이언트는 웹 브라우저 html 렌더링 -> 우리가 보는 화면.

HTTP(HyperText Transfer Protocol)

  • 모든 것이 HTTP
  • 클라이언트 서버 구조
  • Stateful / Stateless
  • 비 연결성(connectionless)
  • 단순함, 확장 가능
  • HTTP 메시지
  • HTTP/1.1 버전을 많이 사용한다.

HTTP 메시지에 담을 수 있는것들

  • HTML, TEXT
  • Image, 음성, 영상, 파일
  • JSON, XML(API)
  • 거의 모든 형태의 데이터 전송 가능
  • 서버간 데이터 주고받을 때도

클라이언트 서버 구조

  • Request Response 구조
  • 클라 -> 서버 : 요청, 응답 대기.
  • 서버가 요청에 대한 결과를 만들어 응답.
  • 분리, 독립성 확보

무상태 프로토콜(Stateless)

  • 서버가 클라이언트의 상태를 보존하지 않는다.
  • 장점 : 서버 확장성 높다
  • 단점 : 클라이언트가 추가 데이터를 전송한다.

Stateful, Stateless 차이

  • Stateful : 중간에 다른 서버로 바뀌면 안됨.
    • 바뀌게 된다면, 상태 정보를 다른 점원에게 미리 알려야함.
  • Stateless : 중간에 다른 점원으로 바뀌어도 됨.
    • 갑자기 고객이 증가해도, 점원을 많이 투입하면 된다.
    • 클라이언트 요청이 증가해도, 서버를 대거 투입하면 된다.
    • 서버는 클라이언트의 상태를 보관하지 않는다.
    • 대신 클라이언트가 정보를 다 들고 있어야됨
  • Stateless는 응답 서버를 쉽게 바꿀 수 있다 -> 무한한 서버 증설 가능.

Stateless실무한계

  • 모든 것을 무상태로 설계하면 좋겠지만, 아닌 경우도..
  • 무상태 가능
    • 로그인 필요 없는 단순 서비스 소개 화면
  • 상태 유지 해야됨
    • 로그인
  • 로그인한 사용자의 경우 로그인했다는 상태를 서버에 유지해야한다.
  • 일반적으로는 브라우저 쿠키, 서버 세션을 사용해 상태유지를 한다.
  • 상태유지는 데이터를 너무 많이 보내기 때문에, 최소한만 사용하도록 하자.

비 연결성(connectionless)

  • 클라이언트 - 서버가 요청과 응답을 통해 연결된 후에 계속 유지를 해둔다면, 서버는 서버 자원을 계속 소모하게 된다.
  • 요청 - 응답 후에 tcp/ip 연결을 종료하게 되면 서버는 최소한의 자원을 사용하게 되고, 요청을 주고 받을 때만 사용할 수 있게됨.
  • HTTP는 기본이 연결을 유지하지 않는 모델이다.
  • 초 단위 이하의 빠른 속도로 응답.
  • 서버 자원을 매우 효율적으로 사용.
  • 한계와 극복
    • TCP/IP 연결을 새로 맺어야 함 -> 3way handshake 시간 추가.
    • 웹 브라우저로 사이트 요청하면 html뿐 아니라 js, css, 추가 이미지 등 수 많은 자원이 함께 다운로드.
    • 지금은 HTTP 지속 연결(Persistent Connections)로 문제 해결.

킹치만.. Stateless를 ㄱ해줘…

원래는 설명하는 느낌으로 하려했는데 양이 꽤 돼서 걍 정리가 되어버린 나의 글이여

HTTP 메시지

앞서 말했듯, HTTP에는 모든걸 담아서 보낼 수 있다.

  • HTTP 메시지 구조

Start-line 시작라인

HTTP 요청 메시지

  • 얘도 본문 가질 수 잇슴~

예시

GET /search?q=hello&hl=ko HTTP/1.1 << 요 라인!
Host:www.google.com

start-line = request-line / status-line
request-line = method SP request-target SP HTTP-version CRLF

  • HTTP 메서드 : 서버가 수행해야 할 동작 지정.
    - 종류 : GET(조회), POST(이 데이터 처리해줘), PUT(덮어씌워줘), DELETE(지워줘)..
  • 요청 대상 : absolute-path[?query] (절대경로[?쿼리])
    - /로 시작하는 절대경로 뒤에 쿼리가 붙어나오도록
  • HTTP Version

HTTP 응답 메시지

HTTP/1.1 200 OK << 요 라인!
Content-Type: text/html;charset=UTF-8
Content-Length: 3423

<html>
<body></body>
</html>

start-line = request-line / status-line
status-line = HTTP-version SP status-code SP reason-phrase CRLF

  • HTTP 버전
  • HTTP 상태 코드: 요청에 대한 성공 혹은 실패
    - 200 : 성공, 400 : 클라이언트 요청 오류, 500: 서버 내부 오류.

HTTP 헤더

header-field = field-name":" OWS field-vaue OWS
field-name은 대소문자 구분 없다.

//요청부
GET /search?q=hello&hl=ko HTTP/1.1
Host:www.google.com << 요 라인!!



//응답부
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 3423 << 위에랑 얘까지!!

<html>
<body></body>
</html>
  • 용도 : HTTP 전송에 필요한 모든 부가정보
    - ex) 메세지 바디의 내용, 크기, 압축, 인증, 등등..

HTTP 메시지 바디

<html>
<body></body>
</html>
  • 용도 : 실제 전송할 데이터
  • HTML문서, 이미지, 영상, JSON 등, byte로 표현할 수 있는 모든 데이터 전송 가능.

HTTP는 단순하지만, 확장 가능한 기술!

HTTP API

  • API(Application Programming Interface)

리소스 위주의 API를 작성하도록 노오력 해보자.
예시!

- 회원 목록 조회 /members
- 회원 조회 /members/{id}
- 회원 등록 /members/{id}
- 회원 수정 /members/{id}
- 회원 삭제 /members/{id}

엥 entity 위주로 API를 이쁘게 만들긴 했는데, 이러면 조회인지, 등록인지, 수정인지, 삭제인지 어떻게 구분을 할까?

리소스와 행위를 분리하도록 하자.
URI는 리소스만 식별하도록 할거고, 행위는 동사이므로 HTTP 메서드를 사용해 구분해주면 된다.

HTTP method

GET

요청 메시지 예시
GET /search?q=hello&hl=ko HTTP/1.1
Host:www.google.com
  • 리소스를 조회할 때
  • 서버에 전달하고싶은 데이터는 쿼리를 통해 전달한다.
  • 메시지 바디를 사용해 데이터 전달이 가능하지만, 지원하지 않는 곳이 많으므로 지양하자.

클라이언트에서 서버로

GET /members/100 HTTP/1.1
Host:www.google.com

members의 100번 유저 조회해주라

다음과 같은 요청을 보냈다면,
서버에서는 DB를 뒤져 json형태로 값을 반환해준다

/members/100

{
	"username":"무적람쥐",
    "age": 222
}

후에 클라이언트는 서버로부터 다음과 같은 응답 데이터를 받게된다.

HTTP/1.1 200 OK
Content-Type:application/json
Content-Length:34

{
	"username":"무적람쥐",
    "age": 222
}

POST

요청 메시지 예시
POST /members HTTP/1.1
Content-Type:application/json

{
	"username":"hello",
    "age":20
}
  • 요청 데이터를 처리해줭
  • 메시지 바디를 통해 서버로 요청 데이터 전달
  • 서버는 요청 데이터를 처리한다.
  • 주로 전달된 데이터로 신규 리소스 등록, 프로세스 처리에 사용.

클라이언트 -> 서버로 다음과 같은 요청을 보낸다.

POST /members HTTP/1.1
Content-Type:application/json

{
	"username":"hello",
    "age":20
}

서버는 신규 리소스 식별자를 생성하고, 다음과 같은 응답 메시지를 클라이언트에 보낸다.

HTTP/1.1 201 Created
Content-Type:application/json
Content-Length:34
Location:/members/100           <--- 데이터가 삽입된 URI 경로 반환해줌

{
	"username":"hello",
    "age":20
}

처리를 어케해준다는 소리임???

  1. 새 리소스 생성(등록)
    • 서버가 아직 식별하지 않은 새 리소스 생성
  2. 요청 데이터 처리
    • 단순히 데이터를 생성하거나, 변경하는 것을 넘어 프로세스를 처리해야 하는 경우
    • ex) 주문에서 결제완료 -> 배달시작(POST) -> 배달완료 처럼 단순한 값 변경을 넘어, 프로세스의 상태가 변경되는 케이스.
    • POST의 결과로 새로운 리소스가 생성되지 않을 수도 있다.
    • POST //orders/{orderId}/start-delivery (컨트롤 URI)
  3. 다른 메서드로 처리하기 애매한 경우.

PUT

PUT /members/100 HTTP/1.1
Content-Type:application/json

{
	"username":"kim",
    "age":291
}
  • 리소스를 완전히 대체한다
    - 없으면 생성하고, 있으면 리소스를 대체한다
  • 클라이언트가 리소스를 식별한다!
    - 위의 예시는 요청 메세지인데, 클라이언트가 리소스의 위치를 알고, URI를 지정해준다.
    • 포스트는 URI를 서버가 만듬!
  • 리소스를 완전히 대체하므로, 부분 수정이 아님.
기존 데이터
{
	"username":"cat",
    "age":282
}

PUT 요청 보낸 데이터
{
	"age":8888
}

이러면 수정이
{
	"age":8888
}
이렇게 올라감. 

기존에 있던 username 필드는 무시되고, PUT이 지니고 있는 데이터만 무죅건 올라간다.

PATCH

PATCH /member/100 HTTP/1.1
Content-Type:application/json

{
	"age":50
}

이런 식으로 username 필드가 없어도, 기존 데이터에 username, age 필드가 있다면 age 필드만 50으로 수정된다.
PATCH 메소드가 지원이 안되는 버전이라면, POST를 사용하도록 하자.

DELETE

DELETE /members/100 HTTP/1.1
Host: localhost:8080
  • 리소스 제거

HTTP메서드의 속성

안전(Safe Methods)

  • 호출해도 리소스가 변경되지 않는다.
  • GET 메서드는 조회만 하니까 인정

멱등(Idempotent)

  • 반복해서 호출해도 결과가 동일하다.
  • 외부 요인으로 중간에 리소스 변경으로 발생하는 다른 결과는 고려하지 않읍니다.
  • GET : 1억번 조회해도 결과는 같다.
  • PUT : 결과를 아예 덮어씌워 버리니 결과는 같다.
  • DELETE : 백번 지워도 지워졌다는 결과는 동일하다.
  • POST : 멱등 아님!!! 두 번 호출하면 중복결제되는 케이스

캐시가능(Cacheable)

  • 응답 결과 리소스를 캐시해서 사용해도 될까?
    - 이는 리소스와 key가 맞아야 사용이 가능함!
  • GET, HEAD, POST, PATCH (실제로는 GET, HEAD정도만.. url을 key로 잡아 간편하게 사용)
  • POST, PATCH는 메시지 바디까지 캐시 키로 고려해야하는데, 구현이 쉽지 않다.
profile
어?머지?

0개의 댓글