Back/Node

Node.js(Socket.io) + Vue.js 채팅 예제

밍꿔 2020. 3. 6. 18:05


반응형

 

우선 Socket.io는 JavaScript를 이용하여 브라우저 종류에 상관없이 실시간 웹을 구현할 수 있도

 

록 한 기술이다. 또, Socket.io는 WebSocket, FlashSocket, AJAX Long Polling, AJAX Multi part

 

Streaming, IFrame, JSONP Polling을 하나의 API로 추상화한 것이다.

(즉 브라우저와 웹 서버의 종류와 버전을 파악하여 가장 적합한 기술을 선택하여 사용하는 방식)

 

다시 말해 socket.io를 통해 개발을 하면 websocket이 지원이 되지 않는 브라우저에서도 메시지

 

를 양방향으로 주고 받을 수 있다.

 

 

구조는 node.js 기반의 frontend(Vue.js) - client, backend - server 로 나눠서 간다.

 

 

* Backend

 

우선 backend쪽을 보면, root의 app.js에 아래의 코드를 추가한다.

var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);

app.use(express.static(path.join(__dirname, 'public')));

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
app.use('/', indexRouter);
app.use('/users', usersRouter);

app.all('/*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With"); next();
});
app.get('/', function(req, res) {
    res.sendFile('Hi Chating App Server');
});
io.on('connection', function (socket) {

    console.log('Connect from Client: ' + socket)

    socket.on('chat', function (data) {
        console.log('message from Client: ' + data.message)
        var rtnMessage = {
            message : data.message
            ,socketId : data.socketId
        }; // 클라이언트에게 메시지를 전송한다
        socket.broadcast.emit('chat', rtnMessage);
    });
})

server.listen(3001, function() {
    console.log('socket io server listening on port 3001')
})

 

server.listen(3001, function() {
    console.log('socket io server listening on port 3001')
})

여기서 3001번 포트는 아래의 frontend프로젝트에서 소켓객체를 선언할때의 포트와 일치 해야 한다.

 

 

routes/index.js

var express = require('express');
var path = require('path');
var router = express.Router();

router.get('/', function (req, res, next) {
    res.sendFile(path.join(__dirname, '../public', 'index.html'))
});

module.exports = router;

 

 

 

 

* Frontend

 

frontend쪽에서 필요한 라이브러리를 다운 받는다.(marterial은 디자인 관련 파일)

npm install --save vue-material vue-socket.io

 

 

src/main.js

import Vue from 'vue'
import App from './App.vue'
import VueMaterial from 'vue-material'
import 'vue-material/dist/vue-material.css'
import 'vue-material/dist/theme/black-green-light.css'
import Directives from '../plugin/directives'
import io from 'socket.io-client'
import router from './router'

var socket = io('http://localhost:3001')

Vue.config.productionTip = false
Vue.prototype.$socket = socket

Vue.use(VueMaterial)
Vue.use(Directives)

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>',
  render: h => h(App)
}).$mount('#app')

 

socket의 선언부를 보면 위에서 명시한 backend쪽 socket port와 동일하게 맞춰줘야 한다.

 

 

 

src/components/Chat.vue

<template>
  <div class="page-container">
    <md-app>
      <md-app-toolbar class="md-primary">
        <div class="md-toolbar-row">
          <span class="md-title">My Chat App</span>
        </div>
      </md-app-toolbar>
      <md-app-content>
        <md-field>
          <label>Message</label>
          <md-textarea v-model="textarea" disabled v-auto-scroll-bottom></md-textarea>
        </md-field>
        <md-field>
          <label>Your Message</label>
          <md-input v-model="message"></md-input>
          <md-button class="md-primary md-raised" @click="sendMessage()">Submit</md-button>
        </md-field>
      </md-app-content>
    </md-app>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  created () {
    this.$socket.on('chat', (data) => {
      this.textarea += '[' + data.socketId + ']' + data.message + '\n'
    })
  },
  data () {
    return {
      textarea: '',
      message: '',
      socketId: ''
    }
  },
  methods: {
    sendMessage () {
      this.$socket.emit('chat', {
        message: this.message,
        socketId: this.$socket.id
      })
      this.textarea += '[' + this.$socket.id + ']' + this.message + '\n'
      this.message = ''
      this.socketId = this.$socket.id
    }
  }
}
</script>

<style>
  .md-app {
    height: 800px;
    border: 1px solid;
  }
  .md-textarea {
    height: 300px;
  }
</style>

 

서버에서 emit을 통해 client로 메세지를 전달 하였고 client에서 같은 이벤트를 사용하여 서버로부터 데이터를 받도록 한다.

 

 

src/router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

import IndexPage from '@/components/IndexPage'
import LoginPage from '@/components/LoginPage'
import Chat from '@/components/Chat'


export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'IndexPage',
      component: IndexPage
    },
    {
      path: '/loginPage',
      name: 'LoginPage',
      component: LoginPage
    },
    {
      path: '/chat',
      name: 'Chat',
      component: Chat
    }
  ]
})

router 설정

 

 

plugins/directive.js

module.exports = (Vue) => {
  Vue.directive('auto-scroll-bottom', {
    update: (el) => {
      el.scrollTop = el.scrollHeight
    }
  })
}

 

스크롤관련js. 추가로 폴더 및 파일을 생성시켜야된다.

 

 

webpack을 통해 frontend프로젝트 build파일을 backend프로젝트의 public폴더 하위에 

 

위치 시켜 실제 서버 구동은 backend의 서버만 구동하는 방향으로 했지만, 따로 따로 

 

구성해도 된다.

 

 

*결과

 

 

 

참조 : https://javacpro.tistory.com/72

 

 

반응형

'Back > Node' 카테고리의 다른 글

node.js Sequelize - (include, attributes)  (0) 2020.10.30
node.js Sequelize  (0) 2020.09.09
Node.js Express 서버 설치  (0) 2019.02.17
NodeJs설치  (0) 2019.02.17