728x90

Node.js 에서 암호화/복호화하는 예제를 구현 테스트하고 적어둔다.

같은 언어에서 암호화하고 복호화하는 것은 전혀 문제가 없었다.

이기종 언어에서 테스트를 하니까 안되어서 원인 찾느라고 개고생을 했다.

원인은 const iv = Buffer.alloc(16,0); 로 해주는 것을 찾아내는 것이 문제였다.

아래 코드로 REST API 에서 AES256 암호화한 값을 제대로 전달하고, 복호화하는데도 문제가 없다는 걸 확인했다.

 

모듈 설치

npm install crypto --save

 

모듈을 불러와서 사용하는 방법으로 코드를 구현했다.

파일명 : aes_crypto.js

const crypto = require('crypto'); // 암호화 모듈 선언
 
// 암호화 AES256
function AES_encrypt(data, key) {
    const iv = Buffer.alloc(16,0); // 16비트
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    let encryptedText = cipher.update(data, 'utf8''base64');
    encryptedText += cipher.final('base64');
    return encryptedText;
}
 
// 복호화 AES256
function AES_decrypt(data, key) {
    const iv = Buffer.alloc(16,0); // 16비트
    const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
    let decryptedText = decipher.update(data, 'base64''utf8');
    decryptedText += decipher.final('utf8');
    return decryptedText;
}
 
module.exports = { AES_encrypt, AES_decrypt}
// Require()함수는 module.exports를 리턴한다.
 

 

사용 예제

key 를 함수에 포함할까 하다가 별도로 호출하는 방법을 택했다.

key 길이는 반드시 32비트 이어야 한다. 아래 key는 임의로 생성한 키다.

AES 암호화/복호화 함수가 포함된 파일을 require 로 호출하고 aes 로 변수에 할당했다.

// crypto_test.js
const aes = require('./aes_crypto');
 
// 암복호화 KEY
const key = 'Qsj23missdaxX2BjyskV6bs#adada6ds'// 32비트
 
// 암복호화 테스트
let plainText = '내 이름은 홍길동';
let encryptedText = aes.AES_encrypt(plainText, key);
let decryptedText = aes.AES_decrypt(encryptedText, key);
 
console.log('텍스트 : ', plainText);
console.log('암호화 : ', encryptedText);
console.log('복호화 : ', decryptedText);

 

 

 

 

 

 

블로그 이미지

Link2Me

,
728x90

변수

넌적스(nunjucks)에서 변수는 {{ }} 로 감싼다.

변수를 선언할 때는 {% set 변수 = '값' %}를 사용한다.

 

반복문

<ul>
  {% set fruits = ['사과''배''오렌지'' 바나나''복숭아'] %}
  {% for item in fruits %}
  <li>{{item}}</li>
  {% endfor %}
</ul>

 

조건문

조건문은 {% if 변수 %} {% elif %} {% else %} {% endif %}로 이루어져 있다.

{% if isLoggedIn %}
<div>로그인 되었다.</div>
{% else %}
<div>로그인 필요하다.</div>
{% endif %}
 
{% if fruit === 'apple' %}
<p>사과</p>
{% elif fruit === 'banana' %}
<p>바나나</p>
{% elif fruit === 'orange' %}
<p>오렌지</p>
{% else %}
<p>모두 아님</p>
{% endif %}

 

Layout

{% include "header.html" %}
 
{% include "footer.html" %}
 
 
{% extends 'layout.html' %}
 
{% block content %}
{% endblock %}
 
{% block script %}
<script src="/main.js"></script>
{% endblock %}

Layout 에 대한 자세한 사항은 https://mozilla.github.io/nunjucks/templating.html 를 참조하면 된다.

 

 

 

 

 

 

블로그 이미지

Link2Me

,
728x90

제목과 같은 메시지가 출력되어 로그 확인을 해본 결과 패스워드 인식이 제대로 안되는 걸 확인했다.

CentOS 7 .env 환경변수 파일을 만들고 패스워드를 확인해보니 #이 들어간 경우 패스워드를 뒷부분을 주석으로 인식한다는 걸 확인했다. 패스워드 만들 때 주의를 해야 할 사항일 수도 있겠더라.

 

const express = require('express');
const mysql = require('mysql');
const path = require('path');
 
const router = express.Router();
 
require('dotenv').config({ path: '.env'})
 
router.get('/', (req, res,next) => {
   //res.send('home 이후 url');
    console.log(process.env.DB_HOST);
    console.log(process.env.DB_USERNAME);
    console.log(process.env.DB_PASSWORD);
    console.log(process.env.DBNAME);
    res.render('index.html');
});
 
router.get('/login'function(req, res) {
    // Render login template
    res.render('login.html');
});
 
/*
var dbconn  = mysql.createPool({
  connectionLimit : 10,
  host     : 'localhost',
  user     : 'testuser',
  password : 'samplefull!#*',
  database : 'studydb'
});
// */
 
const dbconn  = mysql.createPool({
    connectionLimit : 10,
    host:process.env.DB_HOST,
    user:process.env.DB_USERNAME,
    password:process.env.DB_PASSWORD,
    database:process.env.DBNAME
});

 

주석으로 처리한 것과 같이  DB 접속 정보가 보이는데 보이지 않도록 아래와 같이 처리하는 걸 권장한다.

 

.env 환경변수 파일 내용

 

 

'node.js' 카테고리의 다른 글

Node.js AES 암호화 예제 (이기종 언어간 OK)  (0) 2022.12.06
Node.js nunjucks 기반 Layout  (0) 2022.11.19
[Node.js] ejs View, nunjucks View  (0) 2022.11.18
Node.js jQuery 설치 및 사용  (0) 2022.08.12
nodeJS 유틸리티 상속  (0) 2022.06.09
블로그 이미지

Link2Me

,
728x90

사용자 요청을 처리하는 라우팅 함수를 컨트롤러(Controller), 데이터베이스에 데이터를 저장하거나 조회하는 함수를 Model, 사용자에게 결과를 보여주기 위해 만든 파일을 View 라고 한다.

 

먼저 프로젝트 안에 있는 index.js 파일을 열고 뷰 엔진을 ejs 로 저정한다.

그러면 이제부터는 ejs 로 만든 뷰 템플릿을 사용해 응답을 보낼 수 있다.

app 객체의 set() 메소드는 속성을 설정하는 역할을 한다.

 

ejs 모듈 설치

npm install ejs --save

 

 

index.js

// Package Imports
const express = require('express');
const path = require('path');
 
// App Definition
const app = express();
const port = 3000;
 
// 템플릿 엔진 설정
app.set('views', __dirname + '/views');
app.set('view engine''ejs');
app.engine('html', require('ejs').renderFile);
/***
 * 코드 실행 : <% %>
 * 결과 출력 : <%= %>
 */
 

 

 

nunjucks 모듈 설치

https://mozilla.github.io/nunjucks/getting-started.html

 

Nunjucks

Getting Started User-Defined Templates Warning nunjucks does not sandbox execution so it is not safe to run user-defined templates or inject user-defined content into template definitions. On the server, you can expose attack vectors for accessing sensitiv

mozilla.github.io

위 사이트를 참조해서 npm install nunjucks --save 로 모듈 설치한다.

 

파일을 분리하여 작성하는 방법으로 테스트한 사항을 적어둔다.

index.js 또는 app.js 파일

const express = require('express');
const path = require('path');
let nunjucks = require('nunjucks'); // templating framework
 
// App Definition
const app = express();
 
// Routes 파일 불러오기
const homeRoute = require('./routes/home');
const aboutRoute = require('./routes/about')
const adminRoute = require('./routes/admin');
 
const port = 3000;
 
dotenv.config({ path: './.env'})
 
// 템플릿 엔진 설정
app.set("view engine""html");
nunjucks.configure('views', {
    autoescape: true,
    express: app
});
 
 
app.use('/',homeRoute);
app.use('/about',aboutRoute)
app.use('/admin', adminRoute);
 
app.listen(port,() => {
    console.log('Start On', port);
});
 

 

routes 폴더 밑에 home.js 파일

const express = require('express');
const router = express.Router();
 
 
router.get('/', (req, res,next) => {
   //res.send('home 이후 url');
   res.render('index.html');
});
 
router.get('/login'function(req, res) {
   // Render login template
   res.render('login.html');
});
 
module.exports = router;

여기서 주의할 사항은 res.render('/index.html'); 이라고 하면 절대 안된다.

router.get('/' function(req, res, next){}) 에서 경로 / 가 이미 지정되었기 때문이다.

 

 

routes 폴더 밑에 admin.js 파일

const express = require('express');
const nunjucks = require('nunjucks');
const logger = require('morgan'); // 로그 미들웨어 npm install morgan
// 로그 미들웨어 winston 은 파일로 남기기, DB에 저장, email, sms, 알림 메시지 사용 npm install winston
const bodyParser = require('body-parser');
const router = express.Router();
// 라우터 수준의 미들웨어
 
router.get('/', (req, res) => {
   // res.send('admin 이후 url');
   res.render('admin/index.html');
});
 
router.get('/products', ( _ , res) => {
   res.render( 'admin/products.html' ,
       { message : "hello" } // message 란 변수를 템플릿으로 내보낸다.
   );
});
 
 
module.exports = router;
 

 

 

 

 

views 폴더 내 index.html

파일의 변수를 인식하는 처리 그리고 Layout을 분리하는 구조까지는 처리하지 않았다.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Bootstrap Example</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-light navbar-light">
    <ul class="navbar-nav">
        <li class="nav-item"><class="nav-link" href="/">Home</a></li>
        <li class="nav-item"><class="nav-link" href="/login">Login</a></li>
        <li class="nav-item"><class="nav-link" href="/register">Register</a></li>
        <li class="nav-item"><class="nav-link" href="/admin">Admin</a></li>
    </ul>
</nav>
 
<div class="container">
    <h1>Welcome to My Homepage</h1>
    <h2>Basic Table</h2>
    <p>The .table class adds basic styling (light padding and horizontal dividers) to a table:</p>
    <table class="table">
        <thead>
        <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Email</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>John</td>
            <td>Doe</td>
            <td>john@example.com</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>Moe</td>
            <td>mary@example.com</td>
        </tr>
        <tr>
            <td>July</td>
            <td>Dooley</td>
            <td>july@example.com</td>
        </tr>
        </tbody>
    </table>
</div>
 
</body>
</html>
 

 

위와 같은 구조로 동작된다는 걸 설명하기 위해서 테스트하고 적어둔 것이다.

 

views 폴더 하단에 layout 폴더를 추가하고 html 파일을 분리구조로 만드는 방법은 다음 게시글에 적어둘 것이다.

여기까지는 nunjucks 모듈을 설치하고 view 엔진으로 nunjucks 를 사용하는 간단 방법을 알아봤다.

블로그 이미지

Link2Me

,
728x90

jQuery Ajax를 사용하여 서버와 비동기 통신을 하는 방법이다.

Front-End 단에서 사용하는 loginForm.html 이다. ( 테스트용으로 사용하던 loginForm.php 파일을 약간 수정)

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="form.css"  />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
    $('#login-submit').click(function(e){
        e.preventDefault();
        var userID = $("input[name='userID']");
        if( userID.val() =='') {
            alert("아이디를 입력하세요");
            userID.focus();
            return false;
        }
 
        var password = $("input[name='password']");
        if(password.val() =='') {
            alert("비밀번호를 입력하세요!");
            password.focus();
            return false;
        }
 
        $("form").submit();
    });
});
</script>
</head>
<body>
<div class="container">
<h2>로그인 Form 예제</h2>
<form method="post" action="/login">
    <table>
        <tr>
            <td style="font-size:14px">로그인 ID</td>
            <td><input type="text" name="userID" value=""></td>
        </tr>
        <tr>
            <td style="font-size:14px">패스워드</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan='2' align=left>
                <input type="button" id="login-submit" value="로그인">
            </td>
        </tr>
        <tr>
            <td colspan='2'><p>회원이 아니신가요? <a href="joinForm.html">회원가입 하기</a></p></td>
        </tr>
    </table>
</fom>
</div>
</body>
</html>
 

jQuery 를 CDN 경로로 설정하여 사용하는 것이 편하다.

node_modules/jquery 디렉토리에 설치하여 사용하고자 한다면 ....

npm install jquery --save 를 실행하여 jQuery 라이브러리를 설치한다.

app.js 파일에서 app.use('/node_modules', express.static(path.join(__dirname + '/node_modules'))) 를 추가한다.

loginForm.html 파일에서 <script src="node_modules/jquery/dist/jquery.min.js"></script> 로 수정한다.

 

 

app.js

- public 디렉토리를 static 으로 지정한다.

- express 4.16.0 이상부터 body-parser 를 별도 설치할 필요가 없다.

- form action='/login' 부분이 Back-End app.js 파일 내 app.post('/login', ... ) 에서 처리한다.

- res.render 에서 views 디렉토리 index.ejs 로 값을 넘겨 화면에 출력한다.

var express = require('express');
var path = require('path');
var app = express();
 
 
app.listen(3000function() {
    console.log("start, express server on port 3000");
});
 
app.use(express.static(path.join(__dirname, 'public')));
 
app.set('views', path.join(__dirname, 'views'));
app.set('view engine''ejs');
 
app.use(express.json()); //json 형태로 parsing
app.use(express.urlencoded({ extended: false }));
 
app.get('/'function(req,res) {
    res.sendFile(__dirname + "/publc/index.html");
});
 
app.post('/login'function(req, res) {
    // Form POST 전송의 결과 즉 action='/login'
    var post = req.body;
    console.log(post);
    res.render('index.ejs', {'title':post.userID});
});
 
module.exports = app;

여기서 전달할 데이터 userID 를 {'title' : res.body.userID} 

index.ejs 파일에서 변수로 받는 <%= title %> 에 전달한다.

 

좀 더 완벽하게 Ajax 처리하는 것은 다음에 올릴 예정이다.

블로그 이미지

Link2Me

,
728x90

node.js 에서 유틸리티를 상속하는 예제이다.

ES6 이전버전에서는 유용하겠지만 ES6 이후는 클래스 상속으로 처리하면 된다.

 

// 모듈 로딩
const util = require('util');
 
// 유틸리티 상속
function Parent() {
}
Parent.prototype.sayHello = function () {
    console.log('Hello world, from Parent Class');
}
 
function Child() {
}
util.inherits(Child,Parent); // 상속관계 지정
 
const child = new Child();
child.sayHello();

 

ES6 클래스 상속

// 모듈 로딩
// const util = require('util');
 
// 클래스 구현 : 자바스크립트에서 클래스 사용은 ES6에서부터 지원
class Parent {
    sayHello() {
        return 'Hello world, from Parent Class';
    }
}
 
// 클래스 상속
class Child extends Parent {
}
 
const child = new Child();
console.log(child.sayHello());
 

 

블로그 이미지

Link2Me

,
728x90

동기식 : A 실행 → A 결과 → B 실행 B 결과

- A 결과를 회신 받아서 그 다음 B를 실행한다.

- 동기식은 순차적, 직렬적으로 태스트를 수행한다.

- 동기식은 요청을 보낸 후 응답(결과물)을 받아야지만 다음 동작이 이루어지는 방식이다.

- 결과가 주어질 때까지 아무것도 하지 못하고 대기해야 하는 단점이 있을 수 있다.

// 동기식 함수 구현
function add(a, b) {
    return a + b;
}
 
// 동기식 함수 사용
let result = add(3,4);
console.log('result : ', result);

 

 

비동기식 : A 실행 → B 실행 → A 결과

- A가 비동기로 실행되고 A 결과를 기다리지 않고, 바로 B가 실행되고 난 이후 A의 결과가 나올 수 있다.

- 비동기식은 병렬적으로 태스트를 수행한다. 즉, 요청을 보낸 후 결과와는 상관없이 다음 방식이 동작하는 방식이다.

- 결과가 주어지는데 시간이 걸리더라도 그 시간동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있다.

- 비동기식 처리 예시로는 setTimeout과 AJAX가 있다.

// 비동기식
const fs = require('fs');
fs.readFile("readme.txt""utf8"function (err,content) {
    console.log(content);
});
console.log("Reading files ...");

- 모듈 로딩 : require('모듈이름')

 

callback 함수의 결과가 나중에 실행된다.

// 비동기식 함수 구현
function add(a, b, callback) {
    let result = a + b;
    callback(result);
}
 
// 비동기식 함수 사용
add(3,4,function (result) {
    console.log('result : ', result);
});

 

블로그 이미지

Link2Me

,
728x90

한시간만에 끝내는 Node.js 강의를 듣고 간략하게 내용을 적어둔다.

https://www.youtube.com/watch?v=toLDNN4FQv0 

 

Node.js 설치에 대한 사항은 생략한다.

테스트 환경은 Windows10 이다.

 

먼저 MySQL DB 접속을 위한 샘플 데이타가 필요하여 샘플 데이터를 구해서 DB에 넣었다.

https://link2me.tistory.com/2100

 

MySQL 샘플 DB 설치

MySQL 샘플 DB가 필요해서 설치하는 과정을 적어둔다. https://github.com/datacharmer/test_db 에 접속해서 파일을 다운로드한다. test_db-master.zip 라는 파일이 다운로드 된다. 이제 PC에 설치된 MariaDB 에..

link2me.tistory.com

 

개발툴은 WebStorm 을 사용했다. VSCode 등 툴은 편한 걸 이용하면 된다.

 

 

https://www.npmjs.com/package/mysql 에서 MySQL 설정에 관한 사항을 복사하여 붙여넣기한다.

 

소스코드

 
// server.js 파일 (Terminal 창에서 아래 세줄 실행한다)
// npm install express --save
// npm install ejs --save
// npm install formidable mysql --save
 
const express = require('express');
const app = express();
 
const server = app.listen(3000,() => {
   console.log('Start Server : 3000 port');
});
 
app.set('views', __dirname + '/views');
app.set('view engine''ejs');
app.engine('html', require('ejs').renderFile);
 
app.get('/'function (req, res) {
res.render('index.html');
});
 
app.get('/about'function (req, res) {
    res.send('About Page');
});
 
 
// 구글에서 npm mysql 로 검색하면 찾아지는 게시글에서 복사하여 붙여넣기 한 후, DB설정을 하면 된다.
var mysql = require('mysql');
var pool  = mysql.createPool({
    connectionLimit : 10,
    host            : 'localhost',
    user            : 'root',
    password        : 'autoset',
    database        : 'employees'
});
 
app.get('/db'function (req, res) {
    pool.getConnection(function(err, connection) {
        if (err) throw err; // not connected!
 
        // Use the connection
        connection.query('SELECT * FROM employees LIMIT 10'function (error, results, fields) {
            res.send(JSON.stringify(results));
            console.log('results',results);
            // When done with the connection, release it.
            connection.release();
 
            // Handle error after the release.
            if (error) throw error;
            // Don't use the connection here, it has been returned to the pool.
        });
    });
});
 

 

DB 패스워드는 Autoset10 을 이용하여 Local 에서 DB 테스트를 하기 때문에 설정된 패스워드 그대로 적었다.

 

index.html 파일 → https://www.w3schools.com/ 사이트의 Bootstrap 예제를 가져온 예시 파일이다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Bootstrap Example</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
 
<div class="container">
    <h1>Welcome to My Homepage</h1>
    <h2>Basic Table</h2>
    <p>The .table class adds basic styling (light padding and horizontal dividers) to a table:</p>
    <table class="table">
        <thead>
        <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Email</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>John</td>
            <td>Doe</td>
            <td>john@example.com</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>Moe</td>
            <td>mary@example.com</td>
        </tr>
        <tr>
            <td>July</td>
            <td>Dooley</td>
            <td>july@example.com</td>
        </tr>
        </tbody>
    </table>
</div>
 
</body>
</html>

 

 

 

이제 크롬 브라우저에서 접속해보자.

 

콘솔에도 데이터가 출력되는 걸 확인할 수 있다.

 

블로그 이미지

Link2Me

,
728x90

https://github.com/kairo96/and_node 에서 web 에 폴더 구조를 확인한다.

자세한 내용 확인을 위해서는 책을 구입해야 한다.

책없이 간략하게 동작되는 걸 확인해보고자 한다면 아래 스크립트를 이용하여 node.js 를 설치해 볼 수 있다.

 

# 아래 코드는 root 권한을 가진 관리자 모드에서 실행하기 때문에 #은 주석을 의미한다.
# 방화벽 포트 확인
firewall-cmd --permanent --zone=public --add-port=3000/tcp
firewall-cmd --reload
firewall-cmd --list-all
 
###### nodejs 설치 ##########
yum -y install python gcc-c++ make
 
# 아래 3줄로 설치하면 버전이 낮으니까 이 방식으로 설치하지 말자.
yum -y install epel-release
yum -y install nodejs
yum -y remove nodejs
 
# https://nodejs.org/ 에서 최신버전 LTS를 확인한다.
cd /home
wget https://nodejs.org/dist/v14.15.3/node-v14.15.3-linux-x64.tar.gz
tar xvzf node-v14.15.3-linux-x64.tar.gz
mv node-v14.15.3-linux-x64 nodejs
 
# 실행파일 PATH 지정하기
vi /etc/profile
# pathmunge 윗 줄에 아래 2행 추가
export NODE_HOME=/home/nodejs
export PATH=$PATH:$NODE_HOME/bin
:wq
# 작성한 PATH 적용 시키기
source /etc/profile 
 
# nodejs 버전 확인
node -v
npm -v
 
# nodejs를 실제 설치할 폴더를 만들고 관련 모듈을 설치한다.
cd /home
mkdir node
cd node
 
npm install express-generator -g
# 원래 프로젝트를 생성할 때는 npm init 명령을 사용하지만 express -e www 을 하면 자동으로 만들어진다.
# express-generator 로 설치하면 기본적으로 ejs, jade 모듈은 설치된다.
# jade 기본 형식에서 가장 중요한 것은 들여쓰기이다.
# 들여쓰기는 탭과 띄어쓰기 중 한가지 형태만 사용해야 한다. 혼용하면 에러가 발생한다. 일반적으로 4간 들여쓰기를 한다.
 
express -e www
cd www
npm install
 
# 외부 모듈 설치
npm install formidable mysql --save
 
# nodemon을 어떤 프로젝트에서도 사용할 수 있게 전역으로 설치한다.
npm install nodemon -g
#npm install nodemon --save-dev
 
# npm list 로 설치된 모듈을 확인할 수 있다.
 
# body-parser : POST 요청 데이터를 추출하는 미들웨어
npm install body-parser --save
 
# cookie-parser : 쿠키 요청을 추출하거나 확인하는 미들웨어 모듈
npm install cookie-parser --save
 
# express-session : 세션을 쉽게 생성할 수 있게 도와주는 미들웨어 모듈
npm install express-session --save
 
# 예상하지 못한 오류가 발생했을 때 그 오류를 처리할 수 있는 미들웨어
npm install express-error-handler --save
 
# multer : 파일 업로드하기 위한 미들웨어
# 파일을 업로드할 때는 멀티 파트(multipart) 포멧으로 된 파일 업로드 기능을 사용하며, 
# 파일 업로드 상태 등을 확인할 수 있다.
npm install multer --save
 
# 암호화 저장 미들웨어
npm install crypto --save
 
npm install serve-favicon --save
 
# 로그를 출력하는 미들웨어 모듈 (express 에서 설치되어 있으면 설치할 필요 없음)
npm install morgan --save
 
# 서버 실행 모듈
npm install -g supervisor
# nodejs 같은 단일 쓰레드 기반의 웹 서비스는 예외 하나로 웹 서비스 전체가 죽어버린다.
# 이러한 예외 상황을 대비하고자 만들어진 모듈이 forever 모듈이다.
npm install -g forever
 
#package.json 파일에 추가(fsevents 패키지 모듈은 macOS(OSX)용 이므로 경고 메시지 출력되므로 경고 메시지 제거 목적)
vi package.json
  "optionalDependencies": {
    "fsevents""*"
  }
 
 
# npm 자체 update
npm install -g npm
node -v
npm -v
 
# npm install --no-optional
 
# nodejs 실행
# node는 npm start 명령어를 사용해서 실행하면 app.js 가 실행된다.
# 백그라운드 실행하기 : npm start &
npm start
 
 
# Nodemon은 프로젝트 폴더의 파일들을 모니터링 하고 있다가 파일이 수정되면 서버를 자동으로 restart 시켜주는 패키지이다.
# npm list 로 설치 에러 발생하는 걸 전부 설치해준다.
#nodemon 을 하면 npm start 한 것과 같이 실행된다.
modemon &
 
 
ps -ef | grep node
kill -9 pid_number
 
 
 

 

# CentOS 리눅스를 본인 노트북 또는 PC에 설치하는 방법은 https://link2me.tistory.com/1885 를 따라하면 된다.
# PHP + MariaDB 설치를 하는 것 대신에 MariaDB는 설치하고 node.js 를 설치하면 된다.
 
# Nodemon은 프로젝트 폴더의 파일들을 모니터링 하고 있다가 파일이 수정되면 서버를 자동으로 restart 시켜주는 패키지이다.
# nodemon 을 하면 npm start 한 것과 같이 실행된다.
nodemon &
 
ps -ef | grep node
kill -9 pid_number
 
##### 맛집(bestfood) 앱을 위한 설정 #####
# https://github.com/kairo96/and_node 에서 web 에 폴더 구조를 확인한다.
# 책 저자 사이트인데 MariaDB 테이블 생성 구문에 오타가 있어서 그대로 붙여넣기를 하면 에러가 발생하므로 아래 DB 생성 스크립트를 실행한다.
# routes 폴더에 있는 파일명이 뭔지 체크한다.
# app.js 파일 내용을 확인하고, 내용을 복사하여 붙여넣기 한다.
# db.js 파일을 생성하고 내용 붙여넣기 후 DBname, Username, Password 정보를 수정 입력한다.
# 회원정보 요청 경로는 안드로이드에서는 
 @GET("/member/{phone}")
 Call<MemberInfoItem> selectMemberInfo(@Path("phone") String phone);
# node.js 에서는 /member/:phone 이다.
 
mkdir -p public/member
mkdir -p public/img
cd public
chmod 707 member/
chmod 707 img/
 
############## MariaDB 설치 ##############
mysql -uroot -p
비밀번호 입력 
 
-- DB 생성
drop database bestfood;
create database bestfood default character set utf8;
use mysql;
create user nodejsfox@localhost identified by 'wonderfull!#%';
grant all privileges on bestfood.* to nodejsfox@localhost;
flush privileges;
 
-- 데이터베이스로 이동
use bestfood;
 
-- 맛집 정보 테이블 생성
CREATE TABLE IF NOT EXISTS bestfood_info (
  seq int(11NOT NULL AUTO_INCREMENT,
  member_seq int(11NOT NULL COMMENT '일련번호',
  name varchar(20NOT NULL COMMENT '맛집 이름',
  tel varchar(20NOT NULL COMMENT '전화번호',
  address varchar(50NOT NULL COMMENT '주소',
  latitude double NOT NULL COMMENT '위도',
  longitude double NOT NULL COMMENT '경도',
  description varchar(500NOT NULL COMMENT '설명',
  keep_cnt int(11NOT NULL DEFAULT 0 COMMENT '즐겨찾기 수',
  reg_date timestamp NOT NULL DEFAULT current_timestamp() COMMENT '등록일시',
  PRIMARY KEY (seq)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
-- 맛집 이미지 정보 테이블 생성
CREATE TABLE IF NOT EXISTS bestfood_info_image (
  seq int(11NOT NULL AUTO_INCREMENT,
  info_seq int(11NOT NULL COMMENT '일련번호',
  filename varchar(30NOT NULL COMMENT '이미지 파일 이름',
  image_memo varchar(100NOT NULL COMMENT '이미지 메모',
  reg_date timestamp NOT NULL DEFAULT current_timestamp() COMMENT '등록일',
  PRIMARY KEY (seq)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
-- 즐겨찾기 테이블 생성
CREATE TABLE IF NOT EXISTS bestfood_keep (
  seq int(11NOT NULL AUTO_INCREMENT,
  member_seq int(11NOT NULL COMMENT '사용자 일련번호',
  info_seq int(11NOT NULL COMMENT '맛집 일련번호',
  reg_date timestamp NOT NULL DEFAULT current_timestamp() COMMENT '등록일',
  PRIMARY KEY (seq)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
-- 회원 정보 테이블 생성
CREATE TABLE IF NOT EXISTS bestfood_member (
  seq int(11NOT NULL AUTO_INCREMENT,
  phone varchar(30NOT NULL COMMENT '사용자 전화번호',
  name varchar(30DEFAULT NULL COMMENT '이름',
  sextype varchar(10DEFAULT NULL COMMENT '성별',
  birthday varchar(30DEFAULT NULL COMMENT '생년월일',
  member_icon_filename varchar(50DEFAULT NULL COMMENT '프로필 아이콘',
  reg_date timestamp NOT NULL DEFAULT current_timestamp() COMMENT '등록일',
  PRIMARY KEY (seq)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
#############################################################################
https://link2me.tistory.com/1914 게시글을 보고 지도를 보기 위한 정보를 등록해야 한다.
 
# APP 소스는 오래전 생성된 코드라서 최신 Android Studio 에 맞게 변경해야만 동작된다.
 
 
# Sequelize
npm install sequelize
 
 

 

 

https://github.com/jsk005/food_app 에 androidX 버전으로 수정한 소스를 업로드해두었다.

파이썬 장고 등 다른 언어를 배우느라고 이 소스를 분석하진 않았고 동작이 되는 것만 확인했었다.

Google 지도를 활용하지 않고 Naver 지도를 활용한 어플을 만든 적이 있어 Google Map 은 테스트 용으로만 사용해봤다.

블로그 이미지

Link2Me

,
728x90

CentOS 7.9 환경에서 Node.js 환경을 테스트하고 적어둔다.

 

CentOS 7 환경이 없다면 "윈도우10 환경에서 CentOS 7 설치하기" https://link2me.tistory.com/1885 을 참조하시라.

CentOS 7 기반에서 Node.js 사용 환경 구축은 아래 과정을 따라하기만 하면 된다.

 

먼저 방화벽 설정하는 부분이다.

Node.js 에서 기본 사용하는 3000번 포트를 방화벽에서 허용하도록 한다.

# 아래 코드는 root 권한을 가진 관리자 모드에서 실행하기 때문에 #은 주석을 의미한다.
# 방화벽 포트 확인
firewall-cmd --permanent --zone=public --add-port=3000/tcp
firewall-cmd --reload
firewall-cmd --list-all
 

 

# Node.js 설치

yum -y install python gcc-c++ make

 

# 아래 2줄로 설치하면 버전이 낮으니까 이 방식으로 설치하지 말자.
yum -y install epel-release
yum -y install nodejs
yum -y remove nodejs

 

https://nodejs.org/ 에서 최신버전 LTS를 확인한다.

 

# LTS 버전에 맞게 아래 빨간색을 수정해주고 붙여넣기 하면 된다.

# LTS(Long Term Supported) 버전은 서버 환경에서 안정적으로 동작하도록 지원하는 버전이다.

cd /home
wget https://nodejs.org/dist/v14.15.3/node-v14.15.3-linux-x64.tar.gz
tar xvzf node-v14.15.3-linux-x64.tar.gz
mv node-v14.15.3-linux-x64 nodejs

 

# 실행파일 PATH 지정하기
vi /etc/profile
# pathmunge 윗 줄에 아래 2행 추가
export NODE_HOME=/home/nodejs
export PATH=$PATH:$NODE_HOME/bin
:wq

 

# 작성한 PATH 적용 시키기
source /etc/profile

 

# nodejs 버전 확인
node -v
npm -v

 

# npm(Node Package Manager)는 노드의 패키지를 사용할 수 있도록 설치 및 삭제 등을 지원하는 프로그램

# nodejs를 실제 설치할 폴더를 만들고 관련 모듈을 설치한다.
cd /home
mkdir node

 

# http 모듈만 사용해서 웹 서버를 구성할 때는 많은 것들을 직접 만들어야 한다.

# express 모듈을 사용하면 익스프레스에서 제공하는 미들웨어와 라우터를 사용하여 기능을 편리하게 구성할 수 있다.

 

cd node

npm install express-generator -g

 

# npm install [모듈명] -g  ← 모듈을 전역으로 설치할 때 사용하는 방식이다.


# express-generator 로 설치하면 기본적으로 ejs, jade 모듈은 설치된다.
# jade 기본 형식에서 가장 중요한 것은 들여쓰기이다.
# 들여쓰기는 탭과 띄어쓰기 중 한가지 형태만 사용해야 한다. 혼용하면 에러가 발생한다.

# 일반적으로 4간 들여쓰기를 한다.

 

# view engine 속성은 뷰 엔진을 설정하는 것으로 ejs 나 pug를 많이 사용한다.

# 원래 프로젝트를 생성할 때는 npm init 명령을 사용하지만 express -e www 을 하면 자동으로 만들어진다.
express -e www

 

cd www
npm install

 

 

# 외부 모듈 설치
npm install formidable mysql --save

 

 

 

 

# body-parser : POST 요청 데이터를 추출하는 미들웨어

npm install body-parser --save

 

# cookie-parser : 쿠키 요청을 추출하거나 확인하는 미들웨어 모듈
npm install cookie-parser --save

 

# express-session : 세션을 쉽게 생성할 수 있게 도와주는 미들웨어 모듈
npm install express-session --save

 

# 예상하지 못한 오류가 발생했을 때 그 오류를 처리할 수 있는 미들웨어
npm install express-error-handler --save

# 암호화 저장 미들웨어

npm install crypto --save

 

# multer : 파일 업로드하기 위한 미들웨어
# 파일을 업로드할 때는 멀티 파트(multipart) 포멧으로 된 파일 업로드 기능을 사용하며,
# 파일 업로드 상태 등을 확인할 수 있다.
npm install multer --save

 

npm install serve-favicon --save

 

# 로그를 출력하는 미들웨어 모듈 (express 에서 설치되어 있으면 설치할 필요 없음)
npm install morgan --save

# 서버 실행 모듈
npm install -g supervisor

 

# nodejs 같은 단일 쓰레드 기반의 웹 서비스는 예외 하나로 웹 서비스 전체가 죽어버린다.
# 이러한 예외 상황을 대비하고자 만들어진 모듈이 forever 모듈이다.
npm install -g forever

#package.json 파일에 추가(fsevents 패키지 모듈은 macOS(OSX)용 이므로 경고 메시지 출력되므로 경고 메시지 제거 목적)
vi package.json
  "optionalDependencies": {
    "fsevents": "*"
  }

 

 

# nodemon을 어떤 프로젝트에서도 사용할 수 있게 전역으로 설치한다.

# Nodemon은 프로젝트 폴더의 파일들을 모니터링 하다가 파일 수정되면 서버를 자동 restart 시켜주는 패키지이다.
# nodemon 을 하면 npm start 한 것과 같이 실행된다.
npm install nodemon -g


modemon &

 

파일 수정시 잘못하면 에러 메시지를 보여주기도 하고, 수정사항을 node 재기동없이 처리할 수 있어서 매우 편리하다.

 

이것으로 기본 node.js 환경 구축 설정을 완료했다.

 

모듈 제거

npm uninstall <모듈명>

 

# 전역으로 설치한 패키지 제거

npm uninstall -g <모듈명>

 

모듈 업데이트

npm update <모듈명>

 

# 전역으로 설치한 모듈

npm update -g <모듈명>

 

# 로컬에 설치된 모든 패키지를 의존성 명세서에 맞는 최신 버전으로 업데이트

npm update

 

블로그 이미지

Link2Me

,

nodejs 와 MySQL 연동

node.js 2020. 2. 9. 13:42
728x90

구글에서 검색어 node-mysql 를 입력하면 https://github.com/mysqljs/mysql 를 찾을 수 있다.

Introduction 부분을 참조하면 되는데 설정 파일은 별도로 적어주는 것이 코드 보안상 필요하다.


MySQL DB 연결 설정파일을 만든다. config 디렉토리를 만든 후

vi database_mysql.js 로 필요한 정보를 적어준다.
module.exports = {
  host     : 'localhost',
  user     : 'MySQL username',
  password : 'MySQL password',
  port     : 3306,
  database : 'my_db'
};


DB 연결 테스트 파일 mysql.js 파일을 작성한다.

var dbconfig   = require('./config/database_mysql.js');
var mysql = require('mysql');
var dbconn = mysql.createConnection(dbconfig); //< DB Connection~!!

dbconn.connect(function(err){
    if(!err) {
        console.log("Database is connected!");
    } else {
        console.log("Error connecting database...nn :" + err);
    }

    var sql = "SELECT idx,userID,userNM FROM members LIMIT 2";
    dbconn.query(sql, function(error, rows, fields){
        if(error) {
            console.log(error);
        } else {
            console.log('rows',rows);
            //console.log('fields',fields);
        }
    });
    dbconn.end();
});


3. node mysql.js 를 하면 결과를 출력해줄 것이다.


rows 라고 된 부분이 select 칼럼의 결과를 출력해준다.




연결이 안되고 에러가 발생할 때 나오는 메시지

Error: connect ECONNREFUSED 127.0.0.1:3306 


DB 연결이 안되면
console.log("Error connecting database ... nn:" + err); 메시지를 전송한다.

블로그 이미지

Link2Me

,
728x90

CentOS 6.10에서 APM(Apache + PHP + MariaDB) yum 설치한 환경에서 nodejs 환경 설정


먼저 https://link2me.tistory.com/1559 로 APM 설치과정이 필요하다면 참조한다.


npm install [모듈명] -g

모듈을 전역으로 설치할 때 사용하는 방식이다. g 는 global 을 의미한다.

일반적으로 특정 프로젝트가 아닌 전체 프로젝트에서 공통으로 사용할 수 있는 express-generator 나 nodemon 등을 전역으로 설치한다.


npm install [모듈명] --save

현재 작업중인 프로젝트에 모듈을 설치할 때 사용하는 방식이다.

--save 옵션을 지정하면 현재 프로젝트의 package.json 에 모듈 이름과 버전을 추가한다.


nodejs 는 자체적으로 Web Server 의 역할까지 함께 하므로 별도의 Web Server를 설치할 필요가 없다.


cd /usr/local/nodejs

npm install express-generator -g


이미지에서 보면 lib 디렉토리 하단에 모듈이 설치되는 걸 알 수 있다.


npm install nodemon -g



nodemon 을 설치하는 이유는 Web 서버의 디렉토리에서 npm start 로 nodejs를 실행하면 소스코드를 수정한 사항이 반영되지 않는다. nodemon 을 실행하면 소스코드를 수정할 때마다 서버를 재시작해야 하는 번거로움을 줄일 수 있다.


프로젝트 디렉토리 생성

cd /var/www/html/

express -e bestfood

를 해서 프로젝트 디렉토리를 생성한다.



package.json 에 추가된 모듈을 설치하기 위해 npm install 을 실행한다.

아래 이미지를 보면 node_modules 디렉토리가 추가된 것을 확인할 수 있다.



npm install formidable mysql --save

로 mysql 모듈을 설치한다. (MariaDB 와 내부적으로 95% 이상 동일)


npm  install body-parser


npm install serve-favicon


package.json 파일 내용을 열어보고 미 설치된 것이 있다면 npm install [모듈명] 으로 설치하면 된다.



사용포트 변경

nodejs 는 기본적으로 3000번 포트에서 동작하도록 되어 있다.

방화벽에서 3000번 포트를 open 해주거나 포트를 변경해야 정상 동작한다.

만약 iptime 공유기를 사용한다면, port forwarding 설정을 해줘야 한다.


간단하게 테스트를 위해서 webserver.js 파일을 만들어서 내용을 아래와 같이 적어준다.

IP 주소는 공유기 내부에서 사용하는 IP 주소를 적어준다.

const http = require('http');
// http 모듈에 들어있는 서버 기능을 사용하려면 require()메소드로 http모듈을 불러온다.

const hostname = '192.168.1.11'; // 실제 사용 IP로 변경해야 정상 동작됨
const port = process.env.PORT || 3000

// http 객체의 createServer() 메소드를 호출하면 서버 객체가 반환된다.
http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Welcome to Nodejs Server!!!\n');
}).listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
// 이 서버 객체의 listen() 메소드를 호출하면 웹서버가 시작된다. 


node webserver.js

를 하면

와 같이 나온다.


Web 브라우저에서 동작되는지 테스트를 해본다.

http://ipaddress:3000/

ipaddress 는 public ip address 이다.

확인 방법은 http://www.findip.kr/ 으로 한다.


-------------------------------------------------------------------------------------------------------------

cd /var/www/html/bestfood/bin/

vi www

를 해서 보면


이제

npm start

를 하면 npm 을 이용하여 서버를 실행시킬 수 있다.


package.json 파일 내에 scripts 부분이 실행과 관련된 부분이다.


  "scripts": {
    "start": "node ./bin/www"
  },


  "scripts": {
    "start": "node ./bin/www" ,
    "test": "node ./app.js"
  },
로 수정한 다음에 npm test 를 실행시켜 보라.

npm start 로 실행해서 에러가 발생하면, www 파일 내에서 수정할 사항이 있다는 것이다.


설치된 패키지 확인
기존에 설치된 패키지를 확인할 때는 보통 package.json 파일을 열어 dependencies와 devDependencies 항목을 확인한다.
전체적인 의존성 트리를 확인하고 싶을 때는 npm ls 커맨드를 사용하면 된다.


블로그 이미지

Link2Me

,
728x90

Node.js Express 에서 외장 모듈을 사용하면 파일을 업로드할 수 있다.

파일을 업로드할 때는 멀티 파트(multipart) 포멧으로 된 파일 업로드 기능을 사용하며 파일 업로드 상태 등을 확인할 수 있다.


먼저 cat package.json 로 설치된 모듈 내용을 확인하자.

그림을 보면 multer 1.3.1 이 설치되어 있는 걸 확인할 수 있다.


express는 사용자가 업로드한 파일을 받아서 저장하는 기본 기능을 제공하지 않는다.

별도 모듈 multer 를 설치해줘야 한다.


multer 미들웨어 설치방법

npm install multer --save


아래 코드는 동영상강좌 내용으로 파일 업로드 테스트하고 나서 기록한 것이다.


 // Express 기본 모듈 불러오기
var express = require('express')
  , http = require('http')
  , path = require('path');

// Express의 미들웨어 불러오기
var bodyParser = require('body-parser')
  , cookieParser = require('cookie-parser')
  , static = require('serve-static')
  , errorHandler = require('errorhandler');

// 에러 핸들러 모듈 사용
var expressErrorHandler = require('express-error-handler');

// Session 미들웨어 불러오기
var expressSession = require('express-session');

// 파일 업로드용 미들웨어
var multer = require('multer');
var fs = require('fs');

//클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원
var cors = require('cors');


// 익스프레스 객체 생성
var app = express();

// 기본 속성 설정
app.set('port', process.env.PORT || 3000);

// body-parser를 이용해 application/x-www-form-urlencoded 파싱
app.use(bodyParser.urlencoded({ extended: false }))

// body-parser를 이용해 application/json 파싱
app.use(bodyParser.json())

// public 폴더와 uploads 폴더 오픈
app.use('/public', static(path.join(__dirname, 'public')));
app.use('/uploads', static(path.join(__dirname, 'uploads')));

// cookie-parser 설정
app.use(cookieParser());

// 세션 설정
app.use(expressSession({
    secret:'my key',
    resave:true,
    saveUninitialized:true
}));


//클라이언트에서 ajax로 요청 시 CORS(다중 서버 접속) 지원
app.use(cors());


//multer 미들웨어 사용 : 미들웨어 사용 순서 중요  body-parser -> multer -> router
// 파일 제한 : 10개, 1G
var storage = multer.diskStorage({
    destination: function (req, file, callback) {
        callback(null, 'uploads')
    },
    filename: function (req, file, callback) {
        //callback(null, file.originalname + Date.now())
        var extension = path.extname(file.originalname);
        var basename = path.basename(file.originalname, extension);
        callback(null, basename + Date.now() + extension);
    }
});

var upload = multer({
    storage: storage, // storage 객체
    limits: {
        files: 10, // 한번에 업로드할 수 있는 파일 개수
        fileSize: 1024 * 1024 * 1024
    }
});


// 라우터 사용하여 라우팅 함수 등록
var router = express.Router();

// 파일 업로드 라우팅 함수
// photo.html 파일에서 action 요청 패스 : /process/photo
router.route('/process/photo').post(upload.array('photo', 1), function(req, res) {
    console.log('/process/photo 라우팅 함수 호출됨.');

    try {
        var files = req.files;

        console.dir('#===== 업로드된 첫번째 파일 정보 =====#')
        console.dir(req.files[0]);
        console.dir('#=====#');

        if(files.length > 0){
            console.dir(files[0]);

            // 현재의 파일 정보를 저장할 변수 선언
            var originalname = '',
                filename = '',
                mimetype = '',
                size = 0;

            if (Array.isArray(files)) {   // 배열에 들어가 있는 경우 (설정에서 1개의 파일도 배열에 넣게 했음)
                console.log("배열에 들어있는 파일 갯수 : %d", files.length);

                for (var i = 0; i < files.length; i++) {
                    originalname = files[i].originalname;
                    filename = files[i].filename;
                    mimetype = files[i].mimetype;
                    size = files[i].size;
                }
            }

            console.log('현재 파일 정보 : ' + originalname + ', ' + filename + ', '
                    + mimetype + ', ' + size);

            // 클라이언트에 응답 전송
            res.writeHead('200', {'Content-Type':'text/html;charset=utf8'});
            res.write('<h3>파일 업로드 성공</h3>');
            res.write('<hr/>');
            res.write('<p>원본 파일명 : ' + originalname + ' -> 저장 파일명 : ' + filename + '</p>');
            res.write('<p>MIME TYPE : ' + mimetype + '</p>');
            res.write('<p>파일 크기 : ' + size + '</p>');
            res.end();

        } else {
            console.log('파일이 없습니다');
        }
    } catch(err) {
        console.dir(err.stack);
    }

});

app.use('/', router);


// 404 에러 페이지 처리
var errorHandler = expressErrorHandler({
    static: {
      '404': './public/404.html'
    }
});

app.use( expressErrorHandler.httpError(404) );
app.use( errorHandler );


// Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
  console.log('Express server listening on port ' + app.get('port'));
});


 <!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>파일업로드 테스트</title>
    </head>
<body>
    <h1>파일업로드</h1>
    <br>
    <form method="post" enctype="multipart/form-data" action="/process/photo">
        <table>
            <tr>
                <td><label>파일</label></td>
                <td><input type="file" name="photo" /></td>
            </tr>
        </table>
        <input type="submit" value="업로드" name="submit"/>
    </form>
</body>
</html>


블로그 이미지

Link2Me

,
728x90

Node.js 채팅 기본코드를 좀 더 수정 보완하고 Web 채팅과 안드로이드 채팅이 동시에 되는 걸 확인했다.

Node.js 설치 및 Express, socket.io 설치에 대한 사항은 이전 게시글을 참조하면 된다.




서버 chat.js


 const express = require('express'),
    http = require('http'),
    app = express(),
    server = http.createServer(app),
    io = require('socket.io').listen(server);

app.get('/', (req, res) => {
    res.sendFile(__dirname+'/index.html');
});

var numUsers=0;
var usernames=[];
io.on('connection', (socket) => {
    var addedUser = false;
    socket.on('join', function (username) {
        if (addedUser) return;
        socket.username = username;
        ++numUsers;
        addedUser = true;
        usernames.push(socket.username);
        console.log(socket.username + "님이 접속하셨습니다.");
        console.log('접속한 사용자수 : '+numUsers+'명');
        socket.broadcast.emit('userjoinedthechat', socket.username + "님이 접속하셨습니다.");
        updateUsernames();
    });

    function updateUsernames(){
        io.sockets.emit('usernames', usernames);
    }

    socket.on('messagedetection', (senderNickname, messageContent) => {
        // 서버 콘솔상에 메시지 보여주기
        console.log(senderNickname + " :" + messageContent);
        //message object 생성
        let message = {"message": messageContent, "senderNickname": senderNickname}
        // 클라이언트(Web, Android)로 메시지 전송
        io.emit('message', message); // 나를 포함한 모든 클라이언트에게 전송
    });

    socket.on('disconnect', function () {
        if (addedUser) {
            --numUsers;
            usernames.splice(usernames.indexOf(socket.username), 1);
        }
        console.log(socket.username+"님이 퇴장했습니다");
        console.log('접속한 사용자수 : '+numUsers+'명');
        socket.broadcast.emit("userdisconnect", socket.username + "님이 퇴장했습니다");
        // 나를 제외한 모든 클라이언트에게 전송
        updateUsernames();
    });

});

server.listen(3000, () => {
    console.log('Node chat app is running on port 3000');
});


Web Chatting UI

- css 파일을 별도 분리하여 인식시켰더니 감지를 못하더라. 그래서 같은 파일에 추가했다.

- 채팅 메시지가 많으면 자동으로 가장 하단의 메시지 내용이 보이도록 처리

- 줄바꿈 처리 기능 코드 추가 (스마트폰에서는 엔터키 입력 안되게 처리 코드 추가)

- Web 채팅과 Android 채팅 동시에 가능

- 반응형 화면으로 스마트폰과 PC에서 보이는 화면이 다르게 처리 (커스터마이징 필요)


<!DOCTYPE html>
<html>
<head>
<title>Web Chat Messenger</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" type="text/css" rel="stylesheet">
<style type="text/css">
.container{max-width:1170px; margin:auto;}
img{ max-width:100%;}

.messaging { padding: 0 0 50px 0;}

.inbox_msg {
  border: 1px solid #c4c4c4;
  clear: both;
  overflow: hidden;
}
.inbox_people {
  background: #f8f8f8 none repeat scroll 0 0;
  float: left;
  overflow: hidden;
  width: 35%; border-right:1px solid #c4c4c4;
}
.top_spac{ margin: 20px 0 0;}

.headind_srch{ padding:10px 29px 10px 20px; overflow:hidden; border-bottom:1px solid #c4c4c4;}
.recent_heading {float: left; width:100%;}
.recent_heading h4 {
  color: #05728f;
  font-size: 21px;
  margin: auto;
}

.inbox_chat { height: 550px; overflow-y: scroll;}

.mesgs {
  float: left;
  padding: 20px 5px 5px 10px;
  width: 65%;
}
.msg_history {
  height: 500px;
  overflow-y: auto;
  background: #FFFFFF;
}

.incoming_msg_img {
  display: inline-block;
  width: 6%;
}
.received_msg {
  display: inline-block;
  padding: 0 0 0 10px;
  vertical-align: top;
  width: 92%;
 }
.received_withd_msg { width: 77%;}
.received_withd_msg p {
  background: #F3E2A9 none repeat scroll 0 0;
  border-radius: 3px;
  color: #646464;
  font-size: 14px;
  margin: 0;
  padding: 5px 10px 5px 12px;
  width: 100%;
}
.time_date {
  color: #747474;
  display: block;
  font-size: 12px;
  margin: 8px 0 0;
}

.type_msg {border-top: 1px solid #c4c4c4;position: relative;}
.sent_msg {
  float: right;
  width: 76%;
}
.sent_msg p {
  background: #05728f none repeat scroll 0 0;
  border-radius: 3px;
  font-size: 14px;
  margin: 0; color:#fff;
  padding: 5px 10px 5px 12px;
  width:100%;
}
.outgoing_msg{ overflow:hidden; margin:26px 0 26px;}
.input_msg_write input {
  background: rgba(0, 0, 0, 0) none repeat scroll 0 0;
  border: medium none;
  color: #4c4c4c;
  font-size: 15px;
  min-height: 48px;
  width: 100%;
}

.msg_send_btn {
  background: #05728f none repeat scroll 0 0;
  border: medium none;
  border-radius: 50%;
  color: #fff;
  cursor: pointer;
  font-size: 17px;
  height: 33px;
  position: absolute;
  right: 0;
  top: 11px;
  width: 33px;
}


@media screen and (max-width: 800px) {
    .inbox_msg {
      display: block;
      width: 100%;
    }
    .inbox_people {width: 100%;}
    .inbox_chat { width: 100%;height: 250px;}

    .mesgs {
      display: block;
      width: 100%;
      padding: 20px 0px 10px 0px;
    }
    .msg_history {width: 100%;height: 450px;}
    .type_msg {width: 100%;}

}

</style>
</head>

<body>
<div class="container">
    <!--Form to enter UserName-->
    <div class="row" id="nickWrap">
        <div class="col-xs-9">
            <form id="setNick">
                <input id="username" class="form-control" placeholder="사용자명을 입력하세요"/>
                <input type="submit" class="btn btn-primary">
            </form>
        </div>
    </div>
    <!--end username-->
<div class="messaging" id="contentWrap">
<h3 class=" text-center" id="msg_leave">Messaging</h3>
    <div class="inbox_msg">
        <div class="inbox_people">
          <div class="headind_srch">
            <div class="recent_heading">
              <h4>접속 사용자 현황</h4>
            </div>
          </div>

        <div class="inbox_chat">
            <div class="panel panel-default">
                <div class="panel-body" id="users"></div>
            </div>           
        </div>
    </div>

    <div class="mesgs">
        <div class="msg_history" id="chat">
        </div>

        <div class="type_msg">
            <form id="send-message">
            <div class="input_msg_write">
              <textarea rows="3" id="message" class="form-control" placeholder="메시지를 입력하세요" /></textarea>
              <button class="msg_send_btn" type="button"><i class="fa fa-paper-plane-o" aria-hidden="true"></i></button>
            </div>
            </form>
        </div>
    </div>
</div>

<!--node.js and Jquery code-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script>
<script>
$(function () {
    var socket = io();
    var myname;
    var i;
    var filter = "win16|win32|win64|mac|macintel";

    $('#contentWrap').hide();

    $('#setNick').submit(function () {
        myname = $('#username').val();
        if(myname.length == 0) {
            alert('이름을 입력하세요');
            return false;
        }
        socket.emit('join', myname);
        $('#nickWrap').hide();
        $('#contentWrap').show();
        return false;
    });

    //List of users
    socket.on('usernames', function (message) {
        var html = '';
        for (i = 0; i < message.length; i++) {
            html += message[i] + '<br/>'
        }
        $('#users').html(html);
    });

    $('.msg_send_btn').click(function (e) {
        e.preventDefault();
        msg_send();
    });

    $('#message').keypress(function (e) {
        if ( navigator.platform ) { // 모바일 접속이면 엔터키를 동작 안되게 처리
            if(filter.indexOf( navigator.platform.toLowerCase() ) > 0){
                if (e.which == 13 && !e.shiftKey) { // Shift + Enter키이면 줄바꿈처리 가능
                    msg_send();
                    return false;
                }
            }
        }
    });

    function msg_send(){
        if($('#message').val().length ==0){
            alert('메시지가 입력되지 않았습니다');
            $('#message').focus();
            return false;
        }
        socket.emit('messagedetection', myname, $('#message').val());
        $('#message').val(''); // 메시지를 전송하고 메시지 전송 창 내용을 비운다.
    }

    socket.on('message', function (msg) {
        msg.message = msg.message.replace(/(?:\r\n|\r|\n)/g, '<br />'); // 줄바꿈 처리
        if(myname == msg.senderNickname){ // 내가 전송한 메시지
            $('#chat').append('<div class="outgoing_msg"><div class="sent_msg"><p> '+ msg.message +'</p><span class="time_date">'+new Date().toLocaleString()+'</span></div></div>');
        } else { // 상대방이 보낸 메시지
            $('#chat').append('<div class="incoming_msg"><div class="incoming_msg_img"> <img src="https://ptetutorials.com/images/user-profile.png" alt="sunil"> </div><div class="received_msg"><div class="received_withd_msg"><p>'+ msg.message +'</p><span class="time_date">'+msg.senderNickname+', '+new Date().toLocaleString()+'</span></div></div></div>');
        }
        $("#chat").scrollTop($("#chat")[0].scrollHeight); // 최근 메시지 출력된 내용이 보이게 처리
    });

    socket.on('userjoinedthechat', function (msg) {
        $('#chat').append('<div class="incoming_msg"><div class="incoming_msg_img"></div><div class="received_msg"><div class="received_withd_msg"><p>'+ msg +'</p><span class="time_date">'+new Date().toLocaleString()+'</span></div></div></div>');
        $("#chat").scrollTop($("#chat")[0].scrollHeight); // 최근 메시지 출력된 내용이 보이게 처리
    });
   
    socket.on('userdisconnect', function (msg) {
        $('#chat').append('<div class="incoming_msg"><div class="incoming_msg_img"></div><div class="received_msg"><div class="received_withd_msg"><p>'+ msg +'</p><span class="time_date">'+new Date().toLocaleString()+'</span></div></div></div>');
        $("#chat").scrollTop($("#chat")[0].scrollHeight); // 최근 메시지 출력된 내용이 보이게 처리
    });

});
</script>
</body>
</html>



채팅 UI는 bootstrap 코드를 검색해서 원하는 코드로 변경하면 모바일 Web에서도 깔끔하게 보이게 처리할 수 있을 것이다.

블로그 이미지

Link2Me

,
728x90

CentOS 6.6 에서 Node.js 환경을 구성하는 법은 http://link2me.tistory.com/1344 게시글 참조하면 된다.


웹소켓(Web Socket)은 웹 서버와 웹 브라우저 간의 양방향 통신을 위한 프로토콜이다.
웹 소켓은 클라이언트와 서버의 연결을 항상 유지한다.
연결이 유지된 상태에서 서버 혹은 클라이언트상의 event(이벤트)가 발생하면 event listener에 의해 서버에서 클라이언트로, 또은 클라이언트에서 서버로 데이터의 전달이 이루어진다.
Node.js에서 web socket를 사용하기 위해 socket.io package를 사용한다.

동영상 강좌 등을 보면 Express Generator  를 이용하여 앱 개발하는 방법에 대해 설명을 주로 하고 있다.

http, path, fs, url 등의 모듈은 Node.js에서 기본 제공하는 패키지였기 때문에 설치할 필요가 없지만 Express는 Node.js가 아닌 다른 개인이나 단체가 만든 패키지이기 때문에 npm(node package manager)에서 다운로드 받아야 한다.


먼저 리눅스 쉘 상에서 npm install express-generator -g 를 입력하여 express-generator 을 설치한다.


# npm install express-generator -g

# express -h // 설치 여부 및 도움말 확인

설치하고 싶은 디렉토리에서 다음을 입력하여 디렉토리를 생성한다.

# express www

# cd www && npm install  // 의존성 패키지 설치


이제 socket.io 모듈을 설치한다.

# cd /home/nodejs/www

# npm install socket.io --save

# npm install cors --save

# npm install jquery --save


를 하면 package.json 파일에 버전 정보가 추가된다.




기본적인 채팅 창 구현 예제는 https://www.tutorialbook.co.kr/entry/NodeJS-Express-%EC%99%80-Socketio-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-%EC%B1%84%ED%8C%85-%EC%95%B1-%EB%A7%8C%EB%93%A4%EA%B8%B0?category=587311 사이트에 설명이 잘 되어 있어 참조했다.

단, 그대로 실행하면 에러가 발생한다. 버전 정보를 맞게 수정해줘야 한다.


routers/ 디렉토리에 chat.js 파일을 생성하고 아래 코드를 추가한다.

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

/* GET users listing. */
router.get('/', function(req, res, next) {
    res.render('chat', { title: 'chat function' }); // View 에 chat.jade 를 추가해야됨
});
module.exports = router; 


views 디렉토리에 chat.jade 파일을 생성하고 아래 코드를 추가한다.

extends layout
 
block content
    ul#messages
    form(action='')
      input#m(autocomplete='off')
      button Send
     
    style.
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { padding:0px; font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
 
       
    script(src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js')
    script(src='http://code.jquery.com/jquery-3.3.1.js')
    script.
       
      var socket = io();
       
      $('form').submit(function(){

        // socket.emit('서버로 보낼 이벤트명', 데이터);

        socket.emit('chat message', $('#m').val());
        $('#m').val('');
        return false;
      });
     

      // socket.on('서버에서 받을 이벤트명', function(데이터)
      socket.on('chat message', function(msg){
        $('#messages').append($('<li>').text(msg));
      });
</li>


클라이언트는 socket.on과 socket.emit만 있으면 된다.

위에 색상 표시된 부분은 반드시 package.json 파일에 나온 버전 정보를 확인한 다음에 수정해줘야 정상 동작한다.

즉 설치된 npm 버전과 다르면 동작되지 않는다는 걸 명심하자.

https://cdnjs.com/libraries/socket.io 에서 소켓 관련 버전이 나온 URL를 확인할 수 있다.


 {
  "name": "www",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "^1.4.3",
    "cors": "^2.8.4",
    "debug": "~2.6.9",
    "ejs": "^2.6.1",
    "express": "~4.16.0",
    "express-session": "^1.15.6",
    "http-errors": "~1.6.2",
    "jade": "~1.11.0",
    "jquery": "^3.3.1",
    "morgan": "~1.9.0",
    "multer": "^1.3.1",
    "serve-favicon": "^2.5.0",
    "socket.io": "^2.1.1"
  }
}


app.js 파일 수정내용

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');
var chat = require('./routes/chat'); // 추가

var app = express();
var http = require('http').Server(app); // 추가
var io = require('socket.io')(http); // 추가

// view engine 설정
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade'); // ejs, jade

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.set( "ipaddr", "127.0.0.1" ); // 추가
app.set( "port", 3000 ); // 추가


/*** Routing ***/
app.use('/', routes);
app.use('/users', users);
app.use('/chat', chat); // 추가

http.listen(app.get('port'), function(){
    console.log("Express server listening on port " + app.get('port'));
}); // 추가

// socket.IO : Client 가 연결했을 때의 이벤트 처리
// io는 socket.io 패키지를 import한 변수
// socket은 커넥션이 성공했을 때 커넥션에 대한 정보를 담고 있는 변수
io.on('connection', function(socket){
    console.log('a user connected');
    socket.broadcast.emit('hi'); // 나를 제외한 모든 클라이언트에게 전송

    socket.on('disconnect', function(){
        // disconnect 이벤트는 클라이언트와의 연결이 끊어졌을 때 발생
        console.log('user disconnected');
    });

    socket.on('chat message', function(msg){
        console.log('message: ' + msg);
        io.sockets.emit('chat message', msg); // 나를 포함한 모든 클라이언트에게 전송
        // io.to(socket.id).emit('이벤트명' 데이터); // 특정인 한사람에게 메시지 전송
        // socket.join(방의 아이디); // 그룹에 들어가기
        // socket.leave(방의 아이디); // 그룹 떠나기
        // io.to(방의 아이디).emit('이벤트명', 데이터); // 그룹 전체 메시지 전송
        // socket.broadcast.to(방의 아이디).emit('이벤트명', 데이터); // 나를 제외한 그룹 전체 메시지 전송
        // 그룹의 목록과 그룹 안의 소켓들을 확인하는 방법
        // io.adapter.rooms
        // io.of(네임스페이스).adapter.rooms
        // socket.adapter.rooms
    });

});


// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

module.exports = app;



이제 실행을 하면 될 것이다.

#node app.js


클라이언트에서는

http://xxx.com:3000/chat

이라고 입력하면 입력할 수 있는 화면 창이 뜰 것이다.


웹 화면에서 데이터를 입력하면 접속된 모든 사용자에게 메시지가 전달되므로 본인 화면도 같이 업데이트되어 보이는 걸 확인할 수 있다.


리눅스 서버 상에서 확인하는 메시지 창

으로 user 가 접속된 걸 확인할 수 있다.

하지만 어떤 user가 접속했는지 여부는 알 수 없다.


어떤 user 가 접속했는지 여부를 알 수 있도록 하려면 회원정보와 연동시켜야 한다.

블로그 이미지

Link2Me

,
728x90

안드로이드 채팅 기능을 구현해보고 싶어 구글링 해보니 Firebase 기반으로 만든 채팅 앱 예제가 있다.

하지만 Firebase 기반은 구글 서버에 저장되므로 보안성을 요구하는 곳에서는 사용할 수 없을 거 같다.

그래서 호스팅 서버에서 구현할 수 있는 걸 찾아보니 nodejs 와 socket.io 를 이용하면 좋을 거 같아서 공부중이다.

동영상 강좌는 생활코딩 node.js https://opentutorials.org/course/2136 와 Inflearn 사이트에 있는 https://www.inflearn.com/course/node-js-%eb%85%b8%eb%93%9c%ec%a0%9c%ec%9d%b4%ec%97%90%ec%8a%a4-%ea%b0%95%ec%a2%8c/ 를 듣고 있는 중이다.

Do It Node.js 프로그래밍 책을 보고 있는데 네이버지식인 자료중에 <Node.js 프로그래밍: O'reilly / 한빛출판사> 책을 꼭 보라고 권장하고 있어서 node.js 를 깊게 공부하게 된다면 이 책도 구입 대상이다.

하지만 그럴 일이 있을지 모르겠다. Web 개발은 PHP 로 충분할 거 같고, PHP도 morden PHP 프레임웍을 배워야 하고...


Inflearn 사이트에서 하는 강좌는 WebStorm 툴 기반으로 연습해 볼 수 있는 방법으로 강좌를 진행한다.

WebStorm 툴은 Android Studio 툴을 만든 회사에서 만든 툴이라 그런지 사용방법이 매우 유사하고 편하다.

WebStorm 은 유료 툴로 1년 사용료가 129 달러라고 나온다. 30일 버전으로 사용해보고 있는 중이다.

윈도우 기반에서 편리하게 node.js 동작되는 걸 확인해보는 툴은 무료 툴도 있으니 체험기간동안만 이용해 보련다.

내가 강좌를 듣고 배워서 운영체제는 리눅스 환경이라 express 설치하는 방법이 별로 도움되지 않더라.



Express : Node.js를 위한 빠르고 간결한 개방 웹 프레임워크


http://expressjs.com/ko/ 에 설치방법이 나온다.


1. 새로운 폴더를 생성한다.
   /home/nodejs 를 폴더를 생성했다.
   express 를 테스트할 폴더를 /home/nodejs/express_app를 생성한다.


2. 생성한 폴더로 이동하여 npm init 명령을 이용하여 애플리케이션에 대한 package.json 파일을 작성한다.
   cd /home/nodejs/express_app
   npm init
   entry point: (index.js) app.js 로 적어줬다.


3. npm install express --save
   현재 폴더 하단에 node_modules 폴더가 생성되고 관련 패키지 파일이 생성된다.

   ※ node.js 파일 설치는 /usr/local/nodejs 라는 폴더에 설치하고 설정을 한 상태라서 현재 설치되는 폴더와는 다르다.


4. app.js 파일을 생성한다.
   http://expressjs.com/ko/starter/hello-world.html 에 나온 예제를 그대로 복사하여 붙여넣기 해본다.

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});


5. node app.js 를 하여 실행하고 나서
   클라이언트 웹 브라우저에서 http://weburl:3000 으로 접속을 시도하면 화면에 Hello world! 를 보여주면
   기본적인 준비가 된 상태다.


6. 추가 설치 사항

   npm install express-error-handler --save
   npm install cookie-parser --save
   npm install express-session --save
   npm install multer --save

   npm install ws --save

   npm install socket.io --save

   npm install jquery --save


Express는 HTTP 메소드에 해당하는 다음과 같은 라우팅 메소드를 지원한다.
get, post, put, head, delete, options, trace, copy, lock, mkcol, move, purge, propfind, proppatch, unlock, report, mkactivity, checkout, merge, m-search, notify, subscribe, unsubscribe, patch, search 및 connect.

블로그 이미지

Link2Me

,
728x90

Node.js 서버 환경이 구축되었으니 이제 간단한 웹서버를 만들어서 동작하는지 확인해보자.

 

준비사항

nodejs Web Sever 파일을 저장할 디렉토리를 정한다.

편의상 기존 Web 서버의 하위 디렉토리에 두는 것이 여러모로 편할 거 같아서 /usr/local/apache/htdocs/nodejs 디렉토리를 생성했다.

cd /usr/local/apache/htdocs/nodejs

 

이제 샘플코드를 https://nodejs.org/en/about/ 에서 샘플로 제공한 코드를 EditPlus 에 복사한 다음 코드를 수정했다.

 

const http = require('http');
// http 모듈에 들어있는 서버 기능을 사용하려면 require()메소드로 http모듈을 불러온다.
 
const hostname = '127.0.0.1'// 실제 사용 IP로 변경해야 정상 동작됨
const port = 3000;
 
// http 객체의 createServer() 메소드를 호출하면 서버 객체가 반환된다.
http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type''text/plain' });
  res.end('Welcome to Nodejs Server!!!\n');
}).listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
// 이 서버 객체의 listen() 메소드를 호출하면 웹서버가 시작된다. 

 

 

vi webserver.js 파일을 생성한다.

위에 수정한 코드를 붙여넣기하고 :wq 로 저장하고 빠져나온다.

 

파일을 실행한다.

 

 

Server running 이라고 화면에 나온다.

 

이제 Web 브라우저에서 접속해보자.

라고 화면에 출력되는 것을 확인할 수 있다.

Node.js 가 잘 동작하는 걸 확인할 수 있다.

 

백그라운드 실행

#node webserver.js &

 

프로세스 동작 여부 확인

#ps -ef | grep node

 

프로세스 죽이기

#kill -p PID번호

 

#####################################################

 

express 설치를 해서 Web 서버 만들기

 

 

 

express 모듈은 request 이벤트 리스너를 연결하는데 use() 메소드를 사용한다.

use() 메소드는 여러번 사용할 수 있다.

use() 메소드의 매개변수에는 function(request, response, next) { } 형태의 함수를 입력한다.

use() 메소드의 매개변수에 입력하는 함수를 미들웨어라고 부른다.

요청의 응답을 완료하기 전까지 요청 중간 중간에 여러가지 일을 처리할 수 있다.

// server.js 파일 (Terminal 창에서 아래 두줄 실행한다)
// npm install express --save
// npm install ejs --save
 
const express = require('express');
const app = express();
 
const server = app.listen(3000,() => {
   console.log('Start Server : 3000 port');
});
 
app.set('views', __dirname + '/views');
app.set('view engine''ejs');
app.engine('html', require('ejs').renderFile);
 
app.get('/'function (req, res) {
res.render('index.html');
});
 
app.get('/about'function (req, res) {
    res.send('About Page');
});
 
app.get('/intro'function (req, res) {
    res.render('intro.html');
});
 

 

index.html 파일 → https://www.w3schools.com/ 사이트의 Bootstrap 예제를 가져온 예시 파일이다.

 

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Bootstrap Example</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
 
<div class="container">
    <h1>Welcome to My Homepage</h1>
    <h2>Basic Table</h2>
    <p>The .table class adds basic styling (light padding and horizontal dividers) to a table:</p>
    <table class="table">
        <thead>
        <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Email</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>John</td>
            <td>Doe</td>
            <td>john@example.com</td>
        </tr>
        <tr>
            <td>Mary</td>
            <td>Moe</td>
            <td>mary@example.com</td>
        </tr>
        <tr>
            <td>July</td>
            <td>Dooley</td>
            <td>july@example.com</td>
        </tr>
        </tbody>
    </table>
</div>
 
</body>
</html>

 

 

 

블로그 이미지

Link2Me

,
728x90

채팅 기능을 테스트해보고자 구글링했더니 node.js 서버 환경 구축이 필요하다.

CentOS 6.6 기반에서 node.js 설치하는 방법을 적어둔다.


1. https://www.nodejs.org  사이트에 접속하여 download 사이트로 이동한다.



2. Linux 64-bit 에서 마우스 우클릭하여 링크 주소를 복사한다.

   리눅스에서 다운로드할 경로를 미리 정한다.

   cd /usr/local/ 에서 다운로드 하고 압축을 푼다.  

   wget 복사한 주소를 붙여넣기 한다. 여기서 주의할 점은 https://nodejs.org/dist/v6.11.2/node-v6.11.2-linux-x64.tar.xz 로 나온다.

  wget https://nodejs.org/dist/v6.11.2/node-v6.11.2-linux-x64.tar.gz 로 변경해서 엔터키를 치면 다운로드된다.

  wget https://nodejs.org/dist/v8.12.0/node-v8.12.0-linux-x64.tar.gz


  ※ 2020.1.29일 12.9.1 버전을 받아서 설치했더니 에러가 발생하여 설치 포기하고 8.12.0 버전으로 설치했다.


3. 압축을 푼다.

    tar xvzf node-v6.11.2-linux-x64.tar.gz

    tar xvzf node-v8.12.0-linux-x64.tar.gz


4. mv node-v8.12.0-linux-x64 nodejs 로 디렉토리명을 변경해준다. 경로명을 기억하기 쉽게 하기 위해서....

   cd nodejs 하고 ll 을 하면 bin 폴더 등 이미 인스톨된 상태가 되어 있더라.


5. 실행파일 PATH 지정하기

    #vi /etc/profile

export NODE_HOME=/usr/local/nodejs
export PATH=$PATH:$NODE_HOME/bin

위 그림과 같이 입력하고 :wq 로 저장한다.


6. 작성한 PATH 가 적용되도록 아래 구문을 적어주고 엔터키를 친다.

# source /etc/profile


이제 nodejs 가 제대로 되었는지 확인해본다.


정상적으로 설치되었다면 위 그림처럼 입력한 결과를 출력해줄 것이다.

빠져나오는 것은 .exit 를 입력한다.


node.js 서버 환경 구축은 준비되었다.


7. 방화벽 포트 추가

통신을 하기 위해서는 통신할 포트를 정해야 한다.

포트(port)는 8080 으로 설정하겠다.

#cat /etc/sysconfig/iptables
로 방화벽 설정 상태를 확인한다.



#vi /etc/sysconfig/iptables 편집으로 한줄 추가한 다음 저장하고 빠져나온다.

-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT


방화벽 재시작
#/etc/init.d/iptables restart

변경한 정보 저장(재시작을 하고 나서 저장해야 적용된 정보가 저장됨)
#service iptables save


설치위치 확인
#which node
로 하면 설치 위치를 확인할 수 있다.

#node -v

#npm -v

방화벽 포트 설정까지 마쳤다.

이제 node.js 웹서버 테스트 파일로 통신이 되는지 확인해보자.

블로그 이미지

Link2Me

,