[네트워크] HTTP의 기본 원리와 RESTful 방식 (총 정리)

Q0. 개요

이전 글에서 선수 내용으로 네트워크에 대해 정리를 하였다. 네트워크와 데이터가 전달되는 과정을 먼저 참고하고 네트워크 상의 응용 계층에 있는 HTTP가 내부적으로 어떠한 의미를 가지고 있고, 왜 필요하며, 어떤 다양한 기능들이 제공되는지에 대하여 이번 글에서 정리를 하려고 한다.

2023.11.29 - [오답 노트/Common] - [네트워크] 네트워크의 구조 및 정의 (총 정리)

 

[네트워크] 네트워크의 구조 및 정의 (총 정리)

Q0. 개요 웹 개발을 하면서 자주 사용되는 주요 용어들이 있다. 그 중 네트워크/ 서버/ 클라이언트도 있다. 오늘은 작업하는데 이해도를 높이기 위하여 관련된 내용을 정리하였다. Q1. 클라이언트,

jinu213.tistory.com

 

Q1.  HTTP란 

HyperText Transfer Protocol의 약자. 
있는 그대로를 풀어서 해석하면 하이퍼 텍스트를 전송하는 프로토콜이라는 의미이다.
쉽게 말하면, 클라이언트와 서버의 데이터 통신에서 사용되며 클라이언트에서 HTML, Resource등을 가져온다.


HyperText란, 흔히 알고있는 하이퍼링크를 예로 설명하면 클릭했을때 다른 페이지로 연결되는 기능과 같이 HyperText란 일반적인 텍스트와 다르게 각각의 텍스트들이 서로 링크를 통해 연결된 네트워크 처럼 구성된 문서를 의미한다.

때문에 HTML에서의 HT의 약자도 HyperText를 의미한다.

 

 

Q3.  HTTP를 써야할 이유

원초적인 이유는 웹 브라우저에서 하이퍼텍스트나 리소스를 전달하기 위해 만들었기 때문에 해당 이유로 써야한다.
하지만, 그 외에도 써야할 다양한 이유들이 있기에 HTTP를 써야하는 이유이자 장점을 아래에 정리하였다.

- 텍스트 기반으로 웹 브라우저와 웹 서버간의 소통하는 중간 역할.
- 텍스트 기반으로 간단하게 구현/디버깅/신규 확장에도 용이.
- 네트워크 계층에서 중립적인 프로토콜로 다양한 프로토콜(=TCP, IP, UDP등)을 함께 사용할 수 있어 효율적.
- 네트워크 계층에서 독립적인 프로토콜로 다양한 운영체제와 장치들 간에 웹 통신이 가능. (=어느 장치에서든 이용 가능)
- RESTful 아키텍처가 지원된다. 때문에 RESTful서비스를 이용하여 자원을 표현하고 상태를 전송하는데 적합.
- 프록시라는 서버를 통해 중계 및 캐싱이 지원된다. 이를 통해 네트워크 트래픽 최적화로 성능 향상과 대역폭 절감에 좋다.
- (이전과 현재의) 각각의 요청에 대한 HTTP의 상태는 (저장되지 않고) 독립적으로 처리되는 무상태성 (Stateless)
- 실제로 요청을 주고 받고 응답을 반환하는 프로세스가 끝나면 서버와의 연결을 끊는 비 연결성 (Connectionless)

 

Q4.  HTTP 규격

현재 가장 많이 사용 중인 규격은 2가지가 있다. ( HTTP의 규격이란 상용화해서 사용 중인 버전)
화자의 경우에는 상세한 분석보다는 전체적인 틀을 이해할 수 있을 정도로 간단하게 공부하고 정리를 하였다.

- HTTP/1.1

무난한 스펙. 속도가 HTTP/2에 비해 빠르지는 않지만, 웹 브라우저와의 호환성이나 보안성과 관련되어 문제될 일이 없다.효율적인 시간으로 명령어를 처리하는 파이프라이닝 기법과 지속적인 연결의 장점이 있다.
때문에, 대게 웹 페이지들은 HTTP/1.1로 이루어져 있었다.

 

- HTTP/2

다중화, 헤더 압축, 서버 푸시 등의 기능이 추가되면서 데이터를 전송하는 속도가 HTTP/1.1에 비해 대략 10배 이상 빨라졌다고 한다. 속도가 빨라지면서 확실히 성능 향상은 좋아졌지만, 디도스를 비롯한 여러 웹 해킹과 대한 보안이 취약하거나 특정 웹 브라우저에 대한 호환성이 안좋다는 단점이 있다고 한다. 때문에 아직까지도 HTTP/2는 특별한 목적이 아닌 이상 사용하는데 고민이 필요해 보인다. 
참고로, HTTP/2를 톰캣에 설정하려면 버전은 8.5.15이상부터 사용할 수 있다.

 

- HTTP 규격을 확인하는 방법

웹 페이지를 만들거나 이용하면서 무심코 관심없었던 현재 시스템의 HTTP의 규격은 어떻게 확인하는건지 궁금했다.

먼저 웹 브라우저를 통해 확인하는 방법:
특정 브라우저를 실행시킨다 ☞ 개발자모드(F12)를 띄운다 ☞ 상단의 Network 탭을 클릭한다 ☞ 중간에 Name, Status, Type 등의 항목의 리스트가 있다. 만약 안보인다면 현재 브라우저를 새로고침하면 된다 ☞ 보이는 항목들의 헤더에서 우클릭을 한다 (아무 항목이든 상관없고 헤더이면 된다) ☞ 컨텍스트 메뉴에서 Protocol을 클릭한다.

두번째. 이클립스에 설치된 로컬 서버 (톰캣)에서 확인하는 방법:
이클립스 실행 ☞ (현재 작업 중인 프로젝트 소스와 톰캣이 이미 세팅되어 있다는 전제하에) 대게 좌측에 표시되는 Project Explorer에서 Servers를 열람한다 ☞ 프로젝트 소스 별로 서버 Config폴더가 있다 ☞ 확인할 임의의 Config폴더에서 Server.xml 파일을 열람한다. <Connector> 태그의 protocol옵션을 확인한다.

 

Q5.  HTTP 메소드

HTTP는 웹에서 GET, POST, PUT, DELETE 등의 메서드를 이용하여 정보를 주고받는 프로토콜입니다.
때문에, 클라이언트가 서버에게 수행해야할 동작을 명시하는 것을 의미한다.
처음에는 요청하는 URL의 동작을 한눈에 이해할 수 있는 가독성으로서의 역할로 사용되는 줄 알았다.
하지만 메소드를 사용하지 않는다면, 서버에서 옳바르게 이해하지 못할 수 있기에 원치 않는 응답데이터가 반환될 수 있다.
참고로, HTTP 요청에서 메소드를 사용하지 않으면 서버는 기본적으로 GET메소드를 사용하도록 처리된다.

그 외에 메소드들에 대해 정리한 내용은 아래와 같다.

명칭* 표시개발하면서 제일 많이 사용되는 GET, POST, PATCH, PUT, DELETE를 의미한다.

응답에 BODY가 포함되는지는 각 메서드에 대한 리소스 결과의 정보가 포함되는지를 나타낸 것이다. 안전성오직 조회만 한다면 (안전O). 리소스가 변경된다면 (안전X).멱등같은 요청을 여러 번 해도 결과가 동일하면 (멱등O) 결과가 다르다면 (멱등X)캐시각 브라우저에 반환된 응답 리소스를 저장한다면 (캐시O). 그 말은 즉슨 나머지 PUT, PATCH, DELETE, CONNECT는 브라우저가 주소 캐시를 사용하지 않는다를 의미한다. 반환되는 리소스의 형태의 키가 동일해야 사용할 수 있기 때문에 사용이 쉬운 GET, HEAD를 주로 사용한다.

- HTTP 메소드 호출 방법

더보기

1. GET/ HEAD를 통해 조회에 대해 알아보자.

GET/ HEAD를 요청할 때는 Query String으로 요청 리소스를 전달한다.

대게 하이퍼링크를 클릭하거나, 상단 주소창을 통해 직접 URL을 입력하거나 FORM의 type이 GET인 경우 실행된다.
이 메서드를 이용하면 URL이 그대로 노출되며 바이너리 데이터는 전송이 불가능하다는 단점이 있다.
그리고 다른 POST방식 등과 비교했을 때 속도가 빠르다는 장점이 있다 (그 중에서도 HEAD> GET 빠름)
//클라이언트 
$.ajax({
	url: '/test/selectTestData?id="TEST"',
	type: 'GET',
	success(data){ 
    	console.log(이하 생략...)
        
    }
})

//서버
@RestController //먼저 @RestController라는 @Controller + @ResponseBody를 통해 JSON형태로 객체를 반환한다.
@RequestMapping("/test") //이곳으로 들어올 api의 주소를 매핑하기 위한 설정
public class TestController {
    @equestMapping(value="/saveTestData" method = RequestMethod.GET)
    public void saveTestData(String id){
        System.out.println("이하 생략...");

    }
}

 

 2. PUT/ PATCH/ POST를 통해 신규/변경에 대해 알아보자.

클라이언트의 contentType이나 서버단의 @RequestBody는 신규/변경의 경우 필요한 코드이다.

//클라이언트 
$.ajax({
	url: '/test/saveTestData',
	type: 'POST', //대부분 POST로 통합해서 사용한다.                         
	dataType: 'json',                  
	data: JSON.stringify(json), //클라이언트에서는 데이터를 생성에 대한 메소드를 요청할 때, data(또는 body) 작성하기
	contentType: 'application/json', //클라이언트에서는 데이터를 생성에 대한 메소드를 요청할 때, contextType작성하기
	success(data){ 
    	console.log(이하 생략...)
        
    }
})

//서버
@RestController //먼저 @RestController라는 @Controller + @ResponseBody를 통해 JSON형태로 객체를 반환한다.
@RequestMapping("/test") //이곳으로 들어올 api의 주소를 매핑하기 위한 설정
public class TestController {
    @equestMapping(value="/saveTestData" method = RequestMethod.POST) //대부분 RequestMethod.POST로 통합해서 사용한다.
    public void saveTestData(@RequestBody HashMap<String, Object> map){ //서버에서는 클라이언트에서 전달받은 요청 파라미터를 @RequestBody를 통해 받아야 한다.
        System.out.println("이하 생략...");

    }
}

 

3. 클라이언트에서 리소스 전달방법 (Jquery기준)
참고로, 클라이언트에서 리소스를 전달할 때는
URL을 이용한 Query String과 Http Body에 담아 보내는 방법이 있다.
Http Body에 요청 리소스를 전달하는 방법을 Jquery Ajax기반으로 아래와 같이 정리하였다.

//1. 파라미터가 없을 때:
$.ajax({
    type: 'GET',
    dataType: 'json', // 생략 가능
    contentType: 'application/json', // 생략 가능
    url: 'your_url_here',
    success: function(data) {
        //성공 시 동작
    },
    error: function(error) {
        //에러 시 동작
    }
});

//2. 배열에 JSON이 들어있는 형태일 때:
var jsonDataArray = [
    { key1: 'value1' },
    { key2: 'value2' }
];
$.ajax({
    type: 'POST',
    dataType: 'json', // 생략 가능
    contentType: 'application/json',
    data: JSON.stringify(jsonDataArray),
    url: 'your_url_here',
    success: function(data) {
        //성공 시 동작
    },
    error: function(error) {
        //에러 시 동작
    }
});

//3. 단일 JSON이 넘어갈 때:
var jsonData = { key: 'value' };
$.ajax({
    type: 'POST',
    dataType: 'json', // 생략 가능
    contentType: 'application/json',
    data: JSON.stringify(jsonData),
    url: 'your_url_here',
    success: function(data) {
        //성공 시 동작
    },
    error: function(error) {
        //에러 시 동작
    }
});

//4. 변수 하나만 넘어갈 때:
var singleVariable = 1;
$.ajax({
    type: 'GET',
    dataType: 'json', // 생략 가능
    contentType: 'application/json', // 생략 가능
    data: { yourKey: singleVariable },
    url: 'your_url_here',
    success: function(data) {
        //성공 시 동작
    },
    error: function(error) {
        //에러 시 동작
    }
});

 

하지만, 별도로 상세한 관리 없이 노출되지 않도록 사용하려면 조회/신규/삭제/변경과 관련된 모든 업무를 POST방식으로 Http Body에서 데이터를 전달하는 형태로 구현해도 상관은 없다.

 

Q6.  HTTP 메시지

클라이언트와 서버 간의 데이터를 주고 받는 방식을 의미한다
기본적으로 데이터를 주고 받는 방식은 2가지가 있다.

- Request 요청

클라이언트가 서버에게 요청하는 메시지의 구조는 3가지로 이루어져 있다.
Start Line Headers  ③ Body

- Response 응답

서버가 클라이언트로 응답을 반환하는 메시지의 구조는 4가지로 이루어져 있다.
 Status Line  Headers ③ Body

- HTTP Message 구조

 

메시지의 기본 구조를 찾아서 공부하면서 애매한 키워드들이 많아서 상세하게 다시 정리를 했다.

더보기

  먼저 HTTP 리소스 요청시 메소드 구조에서 Start Line에 표기되는 URL 4가지에 대해 다시 정리한다.

Origin 형태 :  절대 경로로 이루어져 있다. (?와 같은 QueryString이 존재시 포함된다)
Absolute 형태 : 프로토콜, 도메인, 경로 등 모든 정보를 포함.
Authority 형태 :  프로토콜, 호스트(도메인), 선택적으로 포트 번호.
Asterisk 형태 :  CORS에서 리소스를 모든 도메인에 공유하도록 엑세스 하용할 때 사용 ( * 로 표시)


 

● HTTP 리소스 요청 또는 응답시 메소드 구조에서 Header에 대해 다시 정리한다.

1-1. Request Headers : 요청 헤더라고 부른다. 
클라이언트가 서버에게 요청을 보낼 때, 요청에 대한 부가 정보가 담겨 있다.

 

1-2. Response Headers : 응답 헤더라고 부른다. 
클라이언트가 서버에게 응답을 보낼 때, 응답에 대한 부가 정보가 담겨 있다.

 

2. General Headers: 공통 헤더라고 부른다.
요청이나 응답 양쪽 모두 동일하게 적용되는 헤더.
특정 콘텐츠나 요청이 아니라 공통적인 메타데이터가 포함된다. 

 

3. Entity Headers : 엔티티 헤더라고 부른다.
요청이나 응답의 메시지의 (=엔티티) 본문에 대한 정보를 제공한다. 

 

 

- CORS란

Cross Origin Resource Sharing 교차 출처 리소스 공유라고한다.
쉽게 말하면 출처가 다른 리소스 자원을 서로 공유한다는 정책이다.


그렇다면 Cross Origin은 언제 발생되는걸까?
프로토콜이 다른 경우 : https != http 
도메인(=호스트)이 다른 경우 : naver.com != google.com
포트 번호가 다른 경우 : 8080 != 8090

 

 

Q7.  HTTP 상태코드

클라이언트의 HTTP 요청에 대한 서버의 응답 상태를 나타낸다. 
상태 코드는 3자리로 구성되며,  첫 번째 자리의 숫자는 응답의 일반적인 성격을 나타내고, 그 뒤에 상세 의미를 나타낸다.

이러한 HTTP 상태 코드는 클라이언트와 서버 간의 통신 상태를 명확하게 전달하고, 문제 발생 시 적절한 조치를 취할 수 있도록 도와준다.

 

Q8.  REST 방식

REST란, Representational State Transfer의 약자. 웹 서비스를 구현하기 위한 아키텍처 스타일 중의 하나이다.
REST-ful API란 REST 아키텍처를 따르는 웹 서비스를 의미한다.

리소스를 표현하고 리소스간의 상태를 전달하는 방식으로 서비스를 제공된다.
때문에, HTTP 프로토콜을 통해 리소스에 접근하고 조작하는 데 중점을 둔다.

 

  1. 리소스 중심(Resource-Centric):
    • REST는 모든 것을 자원(resource)으로 간주합니다. 각 자원은 고유한 식별자(URI)를 가지며, URI를 통해 해당 자원에 접근한다.
  2. 표현 (Representation):
    • 자원은 여러 표현을 가질 수 있습니다. 예를 들어, JSON, XML, HTML 등 다양한 형식으로 자원을 표현할 수 있다.
  3. 상태 전이 (Stateless):
    • REST는 상태를 관리하지 않습니다. 각 요청은 모든 필요한 정보를 포함하고 있어야 하며, 서버에서는 클라이언트의 상태를 저장하지 않습니다. 이러한 특성은 서비스의 확장성을 높이는 데 기여한다.
  4. 통합 인터페이스 (Uniform Interface):
    • RESTful 서비스는 통일된 인터페이스를 제공된다. 이를 통해 클라이언트와 서버 간의 상호 작용이 단순화되고, 서비스의 확장성과 재사용성이 증가한다.
  5. 계층형 구조 (Layered System):
    • RESTful 서비스는 계층 구조로 구성될 수 있습니다. 각 계층은 특정 역할을 수행하며, 각 계층 간의 통신은 일반적인 인터페이스를 통해 이루어진다.
  6. 캐시 (Cacheable):
    • REST는 캐싱을 지원합니다. 서버에서 응답을 캐시하여 동일한 요청에 대한 성능을 향상시킬 수 있다.
  7. HTTP 메서드 활용: 
    • RESTful 서비스에서는 HTTP 메서드를 활용하여 CRUD(Create, Read, Update, Delete) 작업을 수행한다.

정리하면, RESTful 서비스는 HTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하여 자원을 조작하며, URI를 통해 자원을 식별합니다. 이러한 원칙들에 따라 개발되어, 웹 서비스의 확장성, 클라이언트와 서버간의 상호 작용의 단순성, 유지보수 효율을 증가시키는 데 도움이 된다.