HTTP, Socket, Rest?

YoungMinKim·2020년 12월 4일
1
post-thumbnail

Goal

HTTP, REST에 대한 부분 복습, Spring에서 사용되는 Socket통신에 대해 정리.

01 HTTP란?

  • http 통신은 Hyper Text Transfer Protocol의 약자.
  • 웹에서 사용되는 일반적인 통신 규약이다.
  • Client가 Server에게 자신이 받고 싶은 정보를 request(요청)에 담아 전송한다.
  • Server는 Client의 request에 따라서 알맞은 response(응답)로 응답한다.

즉, Client는 Server에게 자신이 어떤 데이터를 받고싶은지 Server에 요청을 해야, Server가 그 요청에 맞는 데이터를 제공해주는 방식이다.

01-2 HTTP의 특징

  • HTTP의 대표적인 예로는 HTML 문서가 있다.
  • HTTP는 Stateless, Connectionless라는 특징이 있다.

위 상황을 풀어보자면 Client가 Web Browser를 통해 Server에 request(요청)을 보내면, 해당 요청을 받은 Server는 해당 요청에 알맞은
response(응답)을 반환한 후 연결을 끊어 > 독립된 상태를 유지한다.

01-3 HTTP Method

  • GET - 정보 검색 ex) 게시판 리스트 불러오기
  • POST - 실행 / 저장 ex) 회원가입 / 로그인
  • PUT - 전체 수정 ex) 회원정보 전체 수정
  • DELETE - 삭제 ex) 회원정보 삭제
  • PATCH - 일부 수정 ex) 회원정보 일부 수정 (Update에 가장 가깝게 쓰이고 있다)
  • OPTIONS - 시스템에서 지원하는 메소드 확인

02 REST

  • 자원의 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미한다.
  • REST는 어떤 형식을 나타내는 말을 의미 한다.
  • 사이트의 구성 원리를 의미 한다.

위 세 가지의 내용만으로는 REST를 이해하기에는 부족한 것 같다.

02-1 REST 아키텍쳐의 6가지 제한 조건

  • 클라이언트 / 서버 구조
    • 기본적으로 Web Application은 Client(Browser, IOS..) -> Server 구조의 형식이다.
  • 무상태 (Stateless)
    • 위에서 설명한 것처럼, Client가 request(요청)을 보내면 Server는 해당 request에 대한 Response(응답) 반환 후 연결을 끊는다.
  • 캐시 처리 가능 (Cacheable)
  • 계층화 (Layered System)
  • Code on demand (optional)
  • 인터페이스 일관성

HTTP에는 이미 REST 원칙이 녹아 들어 있다.

02-2 REST하게 만든다?

  • URI의 내용만 보고도 해당 API가 어떤 동작을 하는지 알 수 있는 API를 의미 한다.

02-3 REST의 구체적인 개념

  • 자원 명시 -> 해당 자원에 대한 CRUD Operation 적용.
  • <span style-"color:red;">HTTP URI를 통해 자원을 명시하고, HTTP METHOD를 통해 해당 자원에 대한 CRUD Operation 적용.
  • 웹 사이트의 이미지, 텍스트, DB 내용 등의 모든 자원에 고유한 ID인 HTTP URI를 부여한다.

CRUD Operation

  • Create : 생성(POST)
  • Read : 조회(GET)
  • Update : 수정(PUT)
  • Delete : 삭제(DELETE)
  • HEAD: header 정보 조회(HEAD)

03 웹 소켓을 사용해야 하는 이유

  • HTTP만으로 실시간 채팅을 구현하기에는 한계가 있다.
  • HTTP는 요청이 있어야 응답을 하는 구조로 되 있다.

03-1 실시간 채팅 순서

  1. client1이 서버에 메세지를 전송.
  2. Server는 client1의 메시지를 client2에게 전달.
  3. client2는 자신에게 온 메시지를 확인.

하지만 기본적으로 HTTP 통신 원칙에 따르면, Client가 요청을 해야 Server가 응답을 하게 된다. 이러한 이유로 인해 client2는 자신에게 온 메시지를 확인 할 수 가없다.

03-2 해결책

위 같은 단점을 보완하기 위해 나온 기술이 웹 소켓이다.

03-3 웹 소켓?

  • 웹 소켓은 IETF에 의해 RFC6455로 표준화된 엄연한 표준 기술이다.
  • 지속적인 통신을 위해 데이터를 송/수신 할 수 있는 통로를 생성 후 통신 한다.
  • 웹 소켓은 양방향 통신을 지원하기 때문에, clinet의 요청이 없어도 server에서 먼저 정보를 전송한다.
  • 위 같은 이유로 우리는 실시간 채팅 기능을 구현하기 위해서 웹 소켓을 사용해야 하는 것이다.

03-4 Spring 웹 소켓 사용을 위한 의존성 추가

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-websocket</artifactId>
	<version>${org.springframework-version}</version>
</dependency>

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>${jackson.version}</version>
</dependency>

org.springframework

  • Spring 내에서 웹 소켓을 사용할 수 있게 해주는 library.

com.fasterxml.jackson.core

  • 웹 소켓에서 JSON형식으로 데이터를 주고 받기 위해 사용하는 library.

03-5 Servlet.xml 수정

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
	xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	(바뀐line)xmlns:websocket="http://www.springframework.org/schema/websocket"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
	http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
	(바뀐line)http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">

	***생략***
  <websocket:handlers>
		<websocket:mapping handler="echoHandler" path="/echo" />
		<websocket:sockjs />
	</websocket:handlers>
    
	<beans:bean id="echoHandler" class="com.mvc.template.common.socket.EchoHandler"></beans:bean>
  • 위 코드에서 (바뀐 line) 을 기존 프로젝트에 추가해주면 된다.

03-6 EchoHandler 클래스 작성

@RequestMapping("/user/socket/echo")
public class EchoHandler extends TextWebSocketHandler{
    private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>(); //세션 리스트
    private static Logger logger = LoggerFactory.getLogger(EchoHandler.class);

    //클라이언트가 연결 되었을 때 실행
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessionList.add(session);
        logger.info("{} 연결됨", session.getId()); 
    }

    //클라이언트가 웹소켓 서버로 메시지를 전송했을 때 실행
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        logger.info("{}로 부터 {} 받음", session.getId(), message.getPayload());
        //모든 유저에게 메세지 출력
        for(WebSocketSession sess : sessionList){
            sess.sendMessage(new TextMessage(message.getPayload()));
	      }
		}

    //클라이언트 연결을 끊었을 때 실행
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessionList.remove(session);
        logger.info("{} 연결 끊김.", session.getId());
    }
}
  • TextWebSocketHandler상속함으로써 Override 되 있는 메소드를 사용할 수 있다.

03-7 View 페이지 작성

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.5/sockjs.min.js"></script>
</head>
<body>
	<input type="text" id="message" />
	<input type="button" id="sendBtn" value="submit"/>
	<div id="messageArea"></div>
</body>
<script type="text/javascript">
	$("#sendBtn").click(function() {
		sendMessage();
		$('#message').val('')
	});

	let sock = new SockJS("http://localhost:8220/ex/echo/");
	sock.onmessage = onMessage;
	sock.onclose = onClose;
	
	// 메시지 전송
	function sendMessage() {
		sock.send($("#message").val());
	}

	// 서버로부터 메시지를 받았을 때
	function onMessage(msg) {
		var data = msg.data;
		$("#messageArea").append(data + "<br/>");
	}

	// 서버와 연결을 끊었을 때
	function onClose(evt) {
		$("#messageArea").append("연결 끊김");

	}
</script>
</html>
profile
https://ym1085.github.io

0개의 댓글