SSE 방식 말고 Socket.io 라이브러리 사용해서 실시간 데이터 주고받는 법.
라이브러리 설치하기
npm install socket.io
입력하면 끝.
server.js에서 설치한 라이브러리 셋팅한다.
(server.js)
const http = require('http').createServer(app);
const { Server } = require("socket.io");
const io = new Server(http);
server.js 상단에 세줄 추가해줘서 라이브러리 등록한다.
주의 : const app = express() 보다 밑에와야함
(이랬던걸)
app.listen(8080, function () {
console.log('listening on 8080')
});
(이렇게)
http.listen(8080, function () {
console.log('listening on 8080')
});
포트 읽어오던 app.listen() 코드를 http.listen() 으로 수정한다.
express 사용해서 서버를 띄우던걸 http라는 node.js 기본 라이브러리 + socket.io를 이용해서 띄우도록 변경한거다.
socket 해주고 채팅기능 만들어줄 페이지를 만들자.
socket.ejs 파일을 만들고 기본 셋팅해준 뒤, 서버에 get요청 해준다.
(server.js)
app.get('/socket', function(요청,응답){
응답.render('socket.ejs')
});
(socket.ejs)
<script src="jQuery 설치한곳"></script>
<script src="socket.io 설치한곳"></script>
socket.ejs 여기에다가 채팅 기능 개발 해줄거임
그전에 여기 HTML 파일에도 socket.io 라이브러리를 설치해야 한다.
그래야 동일한 문법으로 서버와 채팅을 주고받을 수 있다.
socket.io를 CDN으로 가져오자.
https://cdnjs.com/libraries/socket.io
socket.io cdn 이라고 검색하면 cdn 제공해주는 페이지가 몇개 뜬다.
거기서 파일을 다운받거나 링크를 복사해서 <script>태그로 첨부해주면 된다.
중요한점은, 내가 설치한 socket.io 라이브러리와 동일한 버전을 가져온다.
(package.json을 확인하자)
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.2/socket.io.js" integrity="sha512-zoJXRvW2gC8Z0Xo3lBbao5+AS3g6YWr5ztKqaicua11xHo+AvE1b0lT9ODgrHTmNUxeCw0Ry4BGRYZfXu70weg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
내가 복붙한 코드
이제 진짜 채팅기능 개발하자.
가져온 CDN 링크 하위에 script 태그 열고 개발하면 된다.
<script src="jQuery 설치한곳"></script>
<script src="socket.io 설치한곳"></script>
<script>
var socket = io();
</script>
이렇게 한 줄 추가해주면 웹소켓을 이용해 서버와 실시간 소통채널을 개설한 것이다.
엄청 간단하다....
서버도 누군가 웹소켓으로 접속한걸 캐치할 수 있도록 연결해주자.
(server.js)
io.on('connection', function(){
console.log('연결되었어요');
});
누군가 서버로 connection 했을 때 콘솔창에 출력이 된다.
이제 /socket 경로로 페이지를 방문할 때 마다 자동으로 웹소켓으로 서버와 연결해준다.
socekt.emit()이라는 코드를 사용하면 된다.
버튼을 누르면 전달하게 만들어보자.
(socket.ejs)
<script src="jQuery 설치한곳"></script>
<script src="socket.io 설치한곳"></script>
<button id="send">서버로 데이터 보내기</button>
<script>
var socket = io();
$('#send').click(function(e){
// 실시간 메세지 보내는 법 socket.emit(작명,메세지)
socket.emit('user-send', '안녕하세요~')
})
</script>
emit() 안에는 파라미터 두개를 받는데,
그럼 서버는 'user-send'라는 이벤트명으로 보낸 '안녕하세요~'라는 데이터를 수신할 수 있다.
유저가 보낸 데이터를 서버에서 수신해보자.
(server.js)
// socket.ejs 경로 연결
app.get('/socket', function(요청, 응답){
응답.render('socket.ejs')
});
// 웹소켓에 접속하면 내부 코드 실행시키는 일종의 이벤트리스너
io.on('connection', function(socket){
console.log('유저접속됨');
// 해당 이름으로 메세지 보내면 이거 실행해주셈
socket.on('user-send', function(data){
console.log('유저가 보낸 코드:',data)
})
});
이벤트리스너와 비슷한 문법을 쓴다.
'user-send'라는 이벤트가 발생하면 내부 코드를 실행해달라는 코드다.
function(socket){}으로 파라미터 하나를 넣어주면 유저가 보낸 데이터가 파라미터에 담겨온다.
서버가 유저에게 메세지를 보내고 싶으면
io.emit('작명', '보낼메세지');
이렇게 쓰면 된다.
모든 유저에게 보내는걸 일명 broadcast한다고 함.
서버에서 io.emit()한걸 수신하고 싶다면 이벤트리스너가 필요하다.
(socket.ejs)
<script>
var socket = io();
socket.on('작명', function(data){
console.log(data)
})
</script>
항상 모든 웹소켓 메세지들은 이벤트리스너로 수신할 수 있다.
즉, 단체 채팅방을 만들고 싶다면
(server.js)
io.on('connection', function (socket) {
socket.on('user-send', function (data) {
io.emit('broadcast', data) //모든사람에게 데이터 전송
});
});
이렇게 코드를 짜자.
서버가 모든 사람에게 메세지를 뿌리는 확성기 역할을 해준다.
(socket.ejs)
<script>
var socket = io();
$('#send').click(function(){
socket.emit('user-send', '안녕하쇼')
});
socket.on('broadcast', function(data) {
$('#content').append('<div>' + data + '</div>')
});
</script>
유저는 socket.on 이벤트리스너를 장착해놓으면 서버가 io.emit()하는 데이터를 수신 가능하다.
'broadcast' 이름의 데이터가 도착하면 html로 만들어준다.
데이터 전송시
emit()데이터 수신시on()
다만, 유저->서버 방향이라면socket서버->유저 방향이라면io라고 기억하자.
socket으로 메세지 보낼 땐, id와 header 정보도 전달된다.
io.on('connection', function(socket){
console.log(socket);
});
서버에서 socket이라는 파라미터를 출력해보면,
지금 접속한 유저의 header 정보, 유니크한 socket용 id 등이 출력된다.
특히 socket.id 하면 유저의 유니크한 id를 출력해볼 수 있다.
이걸 이용해서 원하는 사람에게만 메세지를 보내거나 할 수도 있음!
io.on('connection', function(socket){
io.to(socket.id).emit("broadcast", '서버응답임');
});
io.to(소켓아이디).emit() 하면 원하는 소켓 id를 가진 사람에게만 메세지 보내기 가능!
정말 편리한 기능이다!
하위 채팅방을 만들어서 거기 들어있는 사람끼리만 대화할 수 있게 만들기도 가능하다.
서버가 유저를 채팅방에 넣어주면 되는데,
socket.join('room1');
이런 코드를 짜면 room1 이라는 채팅방에 유저를 넣을 수 있다.
채팅방은 미리 만들 필요 없고 그냥 이름만 작명하면 알아서 만들어준다.
GET POST 요청이 아니고 socket으로 한다.
(socket.ejs)
<button id="room1">채팅방1 입장</button>
<button id="room1-send">채팅방1에 메세지 전송</button>
<script>
$('#room1').click(function(){
socket.emit('joinroom', '제발');
});
$('#room1-send').click(function(){
socket.emit('room1-send', '어쩌구저쩌구' )
});
</script>
버튼을 누르면 서버에 요청한다.
(server.js)
io.on('connection', function(socket){
socket.on('joinroom', function(data){
socket.join("room1"); // 1
});
socket.on('room1-send', function(data){
io.to("room1").emit('broadcast', data); // 2
});
});
서버는 요청받은 내용대로 동작시킨다.
채팅방 만들기 끝!
리액트를 내가 만든 서버에서 사용하고 싶으면 어떻게 할까?
서버는 유저가 메인페이지로 접속하면 리액트로 만든 html 파일을 보내주면 연동 끝이다.
임시 서버를 Nodejs + Express로 쉽게 만들어보자.
const express = require('express');
const path = require('path');
const app = express();
app.listen(8080, function () {
console.log('listening on 8080')
});
npm init -y 입력npm install express 입력이러면 웹서버만들기 끝!
서버 미리보기를 띄우고 싶다면 터미널에 nodemon server.js를 입력한다.
nodemon이 없다면 node server.js를 입력해야한다.
server.js 옆에 서브폴더로 리액트 프로젝트 하나를 만든다.
프로젝트를 개발하고 빌드까지 해서 하나의 html으로 만든다.
- 구글에서 nodejs 최신버전 설치
- 터미널에
npx create-react-app 프로젝트명입력- 서브폴더에 생성된 리액트 프로젝트를 VScode로 오픈
- 리액트 문법으로 열심히 개발
- 개발 완료시 터미널에
npm run build- 그 html 파일을 서버에서 필요할 때 유저에게 전송
무슨 서버언어를 쓰던간 리액트로 개발한 html 파일을 고객에게 보내면 그게 서버랑 리액트 합치는 것이다.
build된 폴더안의 파일중 index.html 파일 하나가 html파일이다.
SPA라서 html 파일은 딱 하나다.
이걸 서버에다가 요청하면 리액트와 Nodejs 서버 합치기 끝
(server.js에 추가)
app.use(express.static(path.join(__dirname, 'react-project/build')));
app.get('/', function (요청, 응답) {
응답.sendFile(path.join(__dirname, '/react-project/build/index.html'));
});
express.static 이라는 걸 쓰면 특정 폴더안의 파일들을 static 파일로 고객들에게 잘 보내줄 수 있다.
그럼 build 폴더 안의 css js img 파일들도 잘 사용할 수 있게됨
그리고 늘 하던대로 누군가 / 페이지로 접속하면 리액트로 만든 html 보내주는것임!
리액트 라우터로 /list 페이지를 개발했는데 실제 localhost:8080/list 로 직접 URL 입력 접속하는 경우 아무것도 뜨지 않는다.
왜냐하면 브라우저 URL창에 입력하는건 서버에게 요청하는 것이고 리액트 라우터에게 라우팅 요청하는게 아니기 때문이다.
이걸 리액트가 완전히 라우팅하게 하고 싶다면 server.js에 다음과 같은 코드를 추가해야한다.
(server.js에 추가)
app.get('*', function (요청, 응답) {
응답.sendFile(path.join(__dirname, '/react-project/build/index.html'));
});
별표*는 모든 문자라는 뜻.
-> 고객이 URL란에 무엇이든 넣으면 리액트 프로젝트를 보내주기
이렇게 하면 리액트 라우팅이 잘 된다.
주의: 이 코드는 항상 가장 하단에 놓아야 잘 구동됨
예를 들어 DB에서 글목록 데이터를 꺼내서 HTML로 보여주고 싶을 경우
server-side rendering / client-side rendering 둘 중 하나 선택하면 된다.
server-side rendering은 html을 서버가 만들어서 보내준다.
nodejs 강의처럼
위 3단계를 거친다.
client-side rendering은 html을 리액트가 브라우저안에서 만든다.
리액트를 쓰는 경우 보통 client-side rendering을 한다.
그래서 DB에 있는 상품목록을 가져와서 리액트에서 보여주고 싶다면
- 서버는 누군가 /product로 GET요청을 하면 DB에서 데이터 꺼내서 보내주도록 API 작성
- 리액트는 상품목록을 보여주고 싶을 때 서버 /product 주소로 GET요청
- 받아온 데이터를 html에 집어넣고 개발
예시 ))
// DB에 있던 상품명을 보여주려면?
app.get('/product', function(요청, 응답){
응답.json({name : 'black shoes'})
})
// 유저한테 이 데이터를 쏴준다.
// 그러면 리액트파일에서 상품데이터가 필요하면 /product로 GET요청하면 끝
이렇듯 리액트는 서버와의 통신은 거의 ajax로 진행한다.
POST요청이나 로그인 세션만들기도 ajax로 모두 잘된다.
주의점으론 nodejs 서버파일 상단에
app.use(express.json());
var cors = require('cors');
app.use(cors());
이 코드를 넣고 시작해야 리액트와 nodejs 서버간 ajax 요청이 잘 된다.
그리고 서브프로젝트 터미널에서
npm install cors
를 설치해줘야 한다.
express.json() 은 유저가 보낸 array/object 데이터를 출력해보기 위해 필요하고
cors는 다른 도메인주소끼리 ajax 요청 주고받을 때 필요하다.
그럴 필요 없이 나중에 사이트를 aws, google cloud 이런 곳에 발행할 때 한번만 해주면 된다.
평소 개발시에는 리액트도 localhost로 미리보기 띄워두고 서버도 마찬가지로 개발 진행하면 별 문제 없다.
다만,
리액트 -> 서버 ajax 요청시 /product 이렇게 말고 http://서버주소/product 잘 입력하고
서버에 cors 옵션 잘 켜놓으면 된다.