SSE(Server-Sent Events) HTTP ๊ธฐ๋ฐ์ผ๋ก ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ค์๊ฐ์ผ๋ก ์ ์กํ๋ ๋จ๋ฐฉํฅ ํต์ ๊ธฐ์ ์ ๋๋ค
๋ณดํต ํด๋ผ์ด์ธํธ๊ฐ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ธฐ ์ํด ์๋ฒ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ์ง๋ง, SSE๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์์ด๋ ์๋ฒ๊ฐ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ ๊ฒ ์ ๋ฌ๋ ๋ฐ์ดํฐ๋ ์นํ์ด์ง ๋ด์์ Event ๋ฐ์ดํฐ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
SSE์ ์ ์ฌํ ์ค์๊ฐ ๋ฐ์ดํฐ ์ ์ก ๊ธฐ์ ๋ก๋ WebSocket, Polling, HTTP Streaming ๋ฑ์ด ์์ฃผ ์ธ๊ธ๋ฉ๋๋ค.
๊ฐ ๊ธฐ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์๊ณผ ์ฐ๊ฒฐ ์ ์ง ๋ฐฉ์์์ ์ฐจ์ด๋ฅผ ๋ณด์ด๋ฉฐ, ์ฌ์ฉ ๋ชฉ์ ๊ณผ ์ํฉ์ ๋ฐ๋ผ ์ ํฉํ ์ ํ์ด ๋ฌ๋ผ์ง๋๋ค.
์ด๋ฅผ ์ดํดํ๊ธฐ ์ํด, ๊ฐ ๊ธฐ์ ์ ํน์ง์ ๊ฐ๋จํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋จ๋ฐฉํฅ ํต์ ์ ์ ๊ณตํ๋ SSE์๋ ๋ค๋ฅด๊ฒ WebSocket์ ์๋ฐฉํฅ ํต์ ์ ์ ๊ณตํฉ๋๋ค.
์ด๊ธฐ HTTP ์์ฒญ์ ํตํด ์ฐ๊ฒฐ์ ์๋ฆฝํ ํ, ๋ณ๋์ ์์ฒญ์ด ์๋๋ผ๋ ์์ชฝ์์ ์์ ๋กญ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์์ต๋๋ค.
๋๋ฌธ์ ์ฑํ , ๊ฒ์ ๋ฑ ์ค์๊ฐ ์๋ฐฉํฅ ํต์ ์ด ํ์ํ ๊ฒฝ์ฐ์ ์ฃผ๋ก ์ฌ์ฉ๋ฉ๋๋ค. ๋ค๋ง, ๋ณ๋์ ํ๋กํ ์ฝ์ ์ฌ์ฉํ๊ณ ์ฐ๊ฒฐ ๋ฐ ์ํ๋ฅผ ์ง์ ๊ด๋ฆฌํด์ผ ํ๊ธฐ ๋๋ฌธ์ SSE์ ๋น๊ตํ์ ๋ ๊ตฌํ ๋ณต์ก๋๊ฐ ๋์ ํธ์ ๋๋ค.
Polling์ ํด๋ผ์ด์ธํธ๊ฐ ์ผ์ ํ ์ฃผ๊ธฐ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ด ์๋ก์ด ๋ฐ์ดํฐ๊ฐ ์๋์ง ํ์ธํ๋ ๋ฐฉ์์ ๋๋ค.
๊ตฌํ์ด ๋จ์ํ์ง๋ง, ๋ฐ์ดํฐ ๋ณ๊ฒฝ์ด ์๋๋ผ๋ ์ง์์ ์ผ๋ก ์์ฒญ์ ๋ณด๋ด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋นํจ์จ์ ์ผ๋ก ์์ฉํ ์ ์์ต๋๋ค.
ํนํ ์์ฒญ ๊ฐ๊ฒฉ์ด ์งง์์๋ก ์๋ฒ ๋ถํ๊ฐ ์ฆ๊ฐํ๊ณ , ๋ฐ๋๋ก ์์ฒญ ๊ฐ๊ฒฉ์ด ๊ธธ์ด์ง๋ฉด ์ค์๊ฐ์ฑ์ด ๋จ์ด์ง๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ์ด๋ฌํ ๋ฌธ์ ์ ์ ๋ณด์ํ๊ธฐ ์ํด SSE์ ๊ฐ์ ์๋ฒ ํธ์ ๊ธฐ๋ฐ์ ํต์ ๋ฐฉ์์ด ๋ฑ์ฅํ๊ฒ ๋์์ต๋๋ค.
HTTP Streaming์ ํ๋์ HTTP ์ฐ๊ฒฐ์ ์ ์งํ ์ํ์์ ์๋ฒ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฐ์์ ์ผ๋ก ์ ์กํ๋ ๋ฐฉ์์ ๋๋ค. ํด๋ผ์ด์ธํธ๋ ์ฐ๊ฒฐ์ ๋์ง ์๊ณ ์คํธ๋ฆผ ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ์์ ํ ์ ์์ต๋๋ค.
SSE๋ HTTP Streaming์ ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฒคํธ ํ์์ ์ ์ํ์ฌ ํ์คํ๋ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋๋ก ๋ง๋ ๊ธฐ์ ์ด๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค.
SSE๋ ํด๋ผ์ด์ธํธ๊ฐ ํ ๋ฒ ์ฐ๊ฒฐ์ ๋งบ์ผ๋ฉด, ์๋ฒ๊ฐ ํด๋น ์ฐ๊ฒฐ์ ์ ์งํ๋ฉด์ ์ง์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค. ์ฐ๊ฒฐ์ด ๋์ด์ง๋ฉด ํด๋ผ์ด์ธํธ๊ฐ ์๋์ผ๋ก ์ฌ์ฐ๊ฒฐ์ ์๋ํ์ฌ ์ฐ๊ฒฐ์ ์ง์์ ์ผ๋ก ์ ์งํฉ๋๋ค.
SSE ์ฐ๊ฒฐ์ ํ๊ธฐ ์ํด์ ๋จผ์ ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ๋ก ์ฐ๊ฒฐ ์์ฒญ์ ๋ณด๋
๋๋ค.
ํด๋ผ์ด์ธํธ๋ EventSource ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋ฒคํธ๋ฅผ ์์ฑํ๋ ์๋ฒ์ ์ฐ๊ฒฐ ์์ฒญ์ ๋ณด๋
๋๋ค.
const eventSource = new EventSource('/events');
ํด๋ผ์ด์ธํธ์์ ์ฐ๊ฒฐ ์์ฒญ์ด ์ค๋ฉด ์๋ฒ๋ ๋ค์๊ณผ ๊ฐ์ ์๋ต ํค๋๋ฅผ ์์ฑํฉ๋๋ค.
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฒ๋ data: Hello!ํ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ด ์ด๋ฒคํธ ์ด๋ฆ์ ํฌํจํ ์๋ ์์ต๋๋ค.
event: message
data: Hello! // -> ์ค์ ๋ฐ์ดํฐ
๊ฐ ๋ฉ์์ง๋ ๋น ์ค \n\n ๋ก ๊ตฌ๋ถํฉ๋๋ค.
์๋ฒ์์ ์ด๋ฒคํธ๊ฐ ์ ์ก๋๋ฉด ํด๋ผ์ด์ธํธ๋ ํด๋น ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํฉ๋๋ค.
eventSource.onmessage = (event) => {
console.log(event.data);
}
event ํ๋๋ฅผ ๊ฐ๋ ์๋ฒ์ ๋ฉ์์ง๋ event ์ ๋ช
์๋ ์ด๋ฆ์ ์ด๋ฒคํธ๋ก ์์ ๋ฉ๋๋ค. (3๋ฒ ๊ณผ์ ์ ์ด๋ฒคํธ ์ด๋ฆ์ ํฌํจํ ํ์ ์ฐธ๊ณ )
eventSource.addEventListener('message', (event) => {
console.log(event.data);
});
SSE๋ ์ฐ๊ฒฐ์ ๊ณ์ ์ ์งํ๊ธฐ ๋๋ฌธ์, ์๋ฒ๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ํด๋น ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ๋ณด๋ผ ์ ์์ต๋๋ค.
๋ค๋ง, ์๋ฌด ๋ฐ์ดํฐ๋ ์์ ๋ ์ฐ๊ฒฐ์ด ๋๊ธธ ์ ์์ต๋๋ค. ๋๋ฌธ์ ์ฐ๊ฒฐ์ด ์ ์ง๋๋๋ก ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฌด์๋ฏธํ ๋ฐ์ดํฐ(beat)๋ฅผ ๋ณด๋ ๋๋ค. ์ด๋ฅผ ๊ธฐ์ ์ Heartbeat๋ผ๊ณ ์นญํฉ๋๋ค.
์ฐ๊ฒฐ์ด ๋์ด์ง๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์ฌ์ฐ๊ฒฐ์ ์๋ํฉ๋๋ค.
retry: 3000
๐ 3์ด ํ ์ฌ์ฐ๊ฒฐ์ ์๋ฏธ
6๋ฒ์์ ์ด์ผ๊ธฐํ๋ฏ์ด ํด๋ผ์ด์ธํธ์ ์๋ฒ๋ ์ฐ๊ฒฐ์ด ๋์ด์ง๋ฉด ์ฐ๊ฒฐ์ด ๋ค์ ์์๋ฉ๋๋ค. ์ฐ๊ฒฐ์ ๋๊ธฐ ์ํด์๋ .close() ๋ฉ์๋๋ก ์ข
๋ฃํ ์ ์์ต๋๋ค.
eventSource.close();
์๋ฒ ์ฐ๊ฒฐ์ด ๋๊ธฐ๊ฑฐ๋, ๋คํธ์ํฌ ๋ฌธ์ , ์๋ชป๋ ๋ฐ์ดํฐ ํฌ๋งท ๋ฑ ์ ์์ ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ ์๋ ์ํฉ์์ ์๋ฌ ์ด๋ฒคํธ๊ฐ ์์ฑ๋ฉ๋๋ค. EventSource ๊ฐ์ฒด์ onerror ์ฝ๋ฐฑ์ ๊ตฌํํ์ฌ ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
eventSource.onerror = (error) => {
alert("SSE ์ฐ๊ฒฐ ์ค๋ฅ ๋ฐ์");
console.log('SSE ์ฐ๊ฒฐ ์ค๋ฅ: ', err);
}
์ด๋ ๊ฒ SSE์ ๊ฐ๋ ๊ณผ ๋์ ๋ฐฉ์์ ๋ํด ์์๋ณด์์ต๋๋ค. ๋ค์ ํฌ์คํ ์์๋ React, SpringBoot๋ก SSE๋ฅผ ์ง์ ๊ตฌํํ์ฌ ์ค์๊ฐ ์๋ฆผ ๊ธฐ๋ฅ์ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๐