Odds and Ends

5장 Node.js 강의 정리 - 웹 서버 만들기 본문

Node.js 강의 정리

5장 Node.js 강의 정리 - 웹 서버 만들기

Squidward 2021. 7. 10. 16:56

[웹 서버 만들기]

1. 간단한 웹 서버 만들기

- http 모듈로 웹 서버를 시작, 노드에 기본으로 들어있는 http모듈로 웹 서버 객체 생성

- createServer() 메소드로 웹 서버 객체 만들고 listen() 메소드로 대기

* listen() 함수란? 서버 실행하여 대기시킴

* close() 함수란? 서버 종료시킴

var http = require('http'); // http 모듈 불러옴

var server = http.createServer(); // 웹서버객체 리턴

// 실제 웹서버, 동작 가능
var host = '자신 WIFI IP주소 넣기'; // 와이파이 변경 시 바꿔줘야함
var port = 3000;
server.listen(port, host, '50000', function(){
    console.log('웹서버가 실행되었습니다 -> ' +host +':'+ port);
});

 

*요청, 응답

var http = require('http');

var server = http.createServer();

var host = '자신 WIFI IP주소 넣기';
var port = 3000;
server.listen(port,host,50000, function(){
    console.log('웹서버 실행됨');
}); 

server.on('connection', function(socket){
    console.log('클라이언트가 접속했습니다.');
});

server.on('request', function(req, res){
    console.log('클라이언드 요청이 들어왔습니다.');
    //console.dir(req);

    res.writeHead(200, {"Content-Type":"text/html;charset=utf-8"});
    res.write('<h1>웹서버로부터 받은 응답</h1>'); // 실제 웹페이지에 응답 보냄
    res.end();
});

결과

- 접속시 connection 이벤트 발생, 요청 받을 시 request이벤트 발생, write()메소드 등을 이용해 응답 전송

**파일을 서버에 읽고 보내기

- POST 방식으로 요청할 때는 request() 메소드 사용

 

2. 익스프레스로 웹 서버 만들기 - 미들웨어,라우터

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

var app = express(); //express 서버 객체

app.set('port',process.env.PORT || 3000); //속성 설정,process.env.PORT은 시스템 환경변수 설정 안되있을 시 3000

var server = http.createServer(app).listen(app.get('port'),function(){ //콜백함수, 웹서버 실행시 동작
    console.log('익스프레스로 웹 서버를 실행함 : ' + app.get('port'));
});

 

Error: Cannot find module 'express' 오류 시 설치해야함

-> npm install express cmd창에 입력해 설치

* 미들웨어란?

: 미들웨어 함수 req(요청) 객체, res(응답) 객체, 그리고 어플리케이션 요청-응답 사이클 도중 그 다음의 미들웨어 함수에 대한 액세스 권한을 갖는 함수이다.

간단하게 말하면 클라이언트에게 요청이 오고 그 요청을 보내기 위해 응답하려는 중간(미들)에 목적에 맞게 처리를 하는, 말하자면 거쳐가는 함수들이라고 보면 되겠다.

** 서버로 전송 방법 두가지

res.writeHead(200,{"Content-Type":"text/html;charset=utf8"});
res.end('<h1>서버에서 응답한 결과입니다. : '+req.user + '</h1>');
var person = {name:'소녀시대',age:20};
res.send(person);//객체 전송

- writeHead()와 end()로 보내는 법, send()를 이용한 법 두가지가 있다.(전자는 메소드를 많이 호출해야해서 send이용)

 

* writeHead()란?

: response 객체의 메소드에서 헤더 정보를 응답에 작성해서 내보내는 것. 첫번째 인자는 상태 코드를 지정하고 두번째인수에 헤더 정보를 연관 배열로 정리한 것이다. 여기에서는 {'Content-Type': 'text/plain'}값이 포함되어 있다. 이로 인해 Content-type이라는 헤더 정보에 'text/plain'의 값을 설정하고 있는 것을 알 수 있다. 이것은 응답으로 반송하는 콘텐츠의 종류를 나타내는 헤더 정보로, 이것으로 "이 콘텐츠는 표준 텍스트이다"라는 것이 클라이언트에 전달된다.

 

[관련 예제 코드]

//app3.js 파일 코드
var express = require('express');
var http = require('http');

var app = express(); // express 서버객체

app.set('port',process.env.PORT || 3000);

app.use(function(req, res, next){ // use는 미들웨어 등록
    console.log('첫번째 미들웨어 호출됨.');

    req.user = 'mike';

    next(); // 이 미들웨어 떠남, 여러개의 미들웨어등록 사용시 이용
});

app.use(function(req,res,next){
    console.log('두번째 미들웨어 호출됨');

    res.writeHead(200,{"Content-Type":"text/html;charset=utf8"});
    res.end('<h1>서버에서 응답한 결과입니다. : '+req.user + '</h1>');
});

var server = http.createServer(app).listen(app.get('port'), function(){
    console.log('익스프레스로 웹 서버를 실행함 ' + app.get('port'));
});
//app6.js 파일
var express = require('express');
var http = require('http');

var app = express();

app.set('port', process.env.PORT || 3000);

app.use(function(req, res, next){
    console.log('첫번째 미들웨어 호출됨');

    var userAgent = req.header('User-Agent');
    var paramName = req.query.name;

    res.send('<h3>서버에서 응답 User-Agent -> '+userAgent+'</h3><h3>Param Name -> ' + paramName+'</h3>')
});

http.createServer(app).listen(app.get('port'), function(){
    console.log('익스프레스에서 웹서버를 실행함' + app.get('port'));
});

3. 미들웨어 사용하기

1. static 미들 웨어 : 특정 폴더의 파일들을 특정 패스로 접근할 수 있도록 열어주는 역할

//static 사용 코드, 특정 폴더 지정해 보안 기능
var express = require('express');
var http = require('http');
var static = require('serve-static');//1.static 불러오기
var path  = require('path');
var app = express();

app.set('port', process.env.PORT || 3000);
app.use('/public',static(path.join(__dirname,'public'))); // 2.static함수로 실행, 폴더 지정, __dirname 실행 장소 의미
//app.use(static(path.join(__dirname,'public'))); // 2.static함수로 실행, 폴더 지정, __dirname 실행 장소 의미

app.use(function(req, res, next){
    console.log('첫번째 미들웨어 호출됨');

    var userAgent = req.header('User-Agent');
    var paramName = req.query.name;

    res.send('<h3>서버에서 응답 User-Agent -> '+userAgent+'</h3><h3>Param Name -> ' + paramName+'</h3>')
});

http.createServer(app).listen(app.get('port'), function(){
    console.log('익스프레스에서 웹서버를 실행함' + app.get('port'));
});

 

지금부터는 실행할 시에 Postman을 이용한다.

 

* Postman 설치하기

크롬 웹스토어에서 Postman을 설치한다.

- 이미지와 같이 입력하고 send 버튼을 입력하면 다음과 같은 결과를 확인할 수 있다.

//app7.js 파일
var express = require('express');
var http = require('http');
var static = require('serve-static');//1.static 불러오기
var path  = require('path');

var bodyParser = require('body-parser');

var app = express();

app.set('port', process.env.PORT || 3000);
app.use('/public',static(path.join(__dirname,'public'))); // 2.static함수로 실행, 폴더 지정, __dirname 실행 장소 의미
//app.use(static(path.join(__dirname,'public'))); // 2.static함수로 실행, 폴더 지정, __dirname 실행 장소 의미

app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

app.use(function(req, res, next){
    console.log('첫번째 미들웨어 호출됨');

    var userAgent = req.header('User-Agent');
    var paramId = req.body.id || req.query.id;

    res.send('<h3>서버에서 응답 User-Agent -> '+userAgent+'</h3><h3>Param Name -> ' + paramId+'</h3>')
});

http.createServer(app).listen(app.get('port'), function(){
    console.log('익스프레스에서 웹서버를 실행함' + app.get('port'));
});

: 미들웨어란 클라이언트의 요청이 들어왔을 때 중간에 가로채서 필요한 기능을 수행해주는 것이다.

 

4. 요청 라우팅하기

: express 로딩했을 때, Router() 함수 실행 가능. 여기서 요청 패스를 발생시키고 콜백함수 지정

* 요청 패스에 따라 라우팅 - 요청패스에 해당하는 함수를 실행

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>로그인</title>
    </head>
    <body>
        <h1>로그인</h1>
        <br>
        <form method="post" action="/process/login"> <!--action이 요청 패스가 된다.-->
            <table>
                <tr>
                    <td>
                        <label>아이디</label>
                        <td><input type="text" name="id"></td>
                    </td>
                    <td>
                        <label>비밀번호</label>
                        <td><input type="password" name="password"></td>
                    </td>
                </tr>
            </table>
            <input type="submit" value = "전송" name="">
        </form>
    </body>
</html>
//app8.js 파일
//static 사용 코드, 특정 폴더 지정해 보안 기능
var express = require('express');
var http = require('http');
var static = require('serve-static');//1.static 불러오기
var path  = require('path');

var bodyParser = require('body-parser');

var app = express();

app.set('port', process.env.PORT || 3000);
app.use('/public',static(path.join(__dirname,'public'))); // 2.static함수로 실행, 폴더 지정, __dirname 실행 장소 의미
//app.use(static(path.join(__dirname,'public'))); // 2.static함수로 실행, 폴더 지정, __dirname 실행 장소 의미

app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());

var router = express.Router();

router.route('/process/login').post(function(req, res){ // 콜백함수
    console.log('/process/login 라우팅 함수에서 받음');

    var paramId = req.body.id || req.query.id;
    var paramPassword = req.body.password || req.query.password;

    res.writeHead(200, {"Content-Type":"text/html;charset=utf8"});
    res.write("<h1>서버에서 로그인 응답</h1>");
    res.write("<div><p>"+paramId+"</p></div>");
    res.write("<div><p>"+paramPassword+"</p></div>");
    res.end();
});

app.use('/', router); // 미들웨어로 등록

app.use(function(req, res, next){
    console.log('첫번째 미들웨어 호출됨');

    var userAgent = req.header('User-Agent');
    var paramId = req.body.id || req.query.id;

    res.send('<h3>서버에서 응답 User-Agent -> '+userAgent+'</h3><h3>Param Name -> ' + paramId+'</h3>')
});

http.createServer(app).listen(app.get('port'), function(){
    console.log('익스프레스에서 웹서버를 실행함' + app.get('port'));
});
app.all('*', function(req, res){
    res.status(404).send('<h1>요청하신 페이지는 없어요.</h1>');
});

[에러처리]

- 지정한 페이지 X, 아무거나 요청으로 입력하면 아래와 같은 결과가 뜨도록 하는 코드이다.

 

 

5. 쿠키와 세션 관리하기

: 쿠키는 클라이언트 웹 브라우저에 저장되는 정보, 세션은 웹 서버에 저장되는 정보

- cookie-parser 미들웨어 사용

- 로그인같은 것 만들 때 쿠키 사용

- 서버가 브라우저의 정보를 받아서 필요할 때 사용

 

https://www.npmjs.com/package/cookie-parser

 

cookie-parser

Parse HTTP request cookies

www.npmjs.com

- 구글에서 정보 검색하여 보는 법, 위의 링크에서 cookie-parser에 대한 정보 확인 가능

 

* express-session이란?

: express-session은 Node.js의 프레임워크인 Express를 사용할 때 세션을 관리할 수 있도록 하는 미들웨어

var expressSession = require('express-session');

app.use(expressSession({
    secret:'my key',
    resave:true,
    saveUninitialized:true
}));

 

아래 세 옵션은 기본적으로 요구되는 옵션으로, 특별한 경우가 아니라면 기본적으로 세 옵션을 모두 사용하면 된다.

  • sercret: 반드시 필요한 옵션으로 세션을 암호화하여 저장함
  • resave: 세션이 변경되지 않아도 계속 저장됨(덮어쓰기) 기본 값은 true이지만 false로 사용할 것을 권장하고있음
  • saveUninitialized: 세션을 초기값이 지정되지 않은 상태에서도 미리 만들어 저장함

6. 파일 업로드 기능 만들기

 

[multer 미들웨어를 이용한 파일 업로드]

- 파일 업로드시 POST 방식으로 요청해야하며 body-parser 미들웨어 사용 필

- fs, cors 모듈도 사용

- ExpressExample폴더에 uploads 폴더를 만들고 이곳에 업로드 되는 파일을 넣는다.

 

[서버에서 파일 업로드하는 예제]

//app13.js 파일
var express = require('express')
  , http = require('http')
  , path = require('path');

var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var expressSession = require('express-session');

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

var app = express();

app.use('/public', express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(expressSession({
  secret: 'my key',
  resave: true,
  saveUninitialized: true
}));

// multer 미들웨어 사용하기
var upload = multer({
  dest: 'uploads',
  putSingleFilesInArray: true,
  limits: {
    files: 10,
    fileSize: 1024*1024
  },
  rename: function (fieldname, filename) {
    return filename + Date.now();
  },
  onFileUploadStart: function (file) {
    console.log('파일 업로드 시작 : ' + file.originalname);
  },
  onFileUploadComplete: function (file, req, res) {
    console.log('파일 업로드 완료 : ' + file.fieldname + '-> ' + file.path);
  },
  onFileSizeLimit: function (file) {
    console.log('파일 크기 제한 초과 : %s', file.originalname);
  }
});

app.post('/process/login', function(req, res) {
  console.log('/process/login 처리함.');

  var paramId = req.param('id');
  var paramPassword = req.param('password');

  if (req.session.user) {
    // 이미 로그인된 상태
    console.log('이미 로그인되어 상품 페이지로 이동합니다.');

    res.redirect('/public/product.html');
  } else {
    // 세션 저장
    req.session.user = {
      id: paramId,
      name: '소녀시대',
      authorized: true
    };
  }

  res.writeHead('200', {'Content-Type': 'text/html;charset=utf8'});
  res.write('<h1>로그인 성공</h1>');
  res.write('<div><p>Param id : ' + paramId + '</p></div>');
  res.write('<div><p>Param password : ' + paramPassword + '</p></div>');
  res.write('<br><br><a href="/public/product.html">상품 페이지로 돌아가기</a>');
  res.end();
});

app.get('/process/logout', function(req, res) {
  console.log('/process/logout 호출됨.');

  if (req.session.user) {
    // 로그인된 상태
    console.log('로그아웃합니다.');

    req.session.destroy(function(err) {
      if(err) throw err;

      console.log('세션을 삭제하고 로그아웃되었습니다.');
      res.redirect('/public/login2.html');
    });
  } else {
    // 로그인 안 된 상태
    console.log('아직 로그인되어 있지 않습니다.');

    res.redirect('/public/login2.html');
  }
});

app.get('/process/users/:id', function(req, res) {
  // 토큰 정보를 가져옴
  var paramId = req.params.id;

  console.log('/process/users와 토큰 %s를 사용해 처리함.', paramId);

  res.writeHead('200', {'Content-Type': 'text/html; charset=utf8'});
  res.write('<h1>Express 서버에서 응답한 결과입니다.</h1>');
  res.write('<div><p>Param id : ' + paramId + '</p></div>');
  res.end();
});

// 쿠키 정보를 확인함
app.get('/process/showCookie', function(req, res) {
  console.log('/process/showCookie 호출됨.');
  res.send(req.cookies);
});

// 쿠키에 이름 정보를 설정함
app.get('/process/setUserCookie', function(req, res) {
  console.log('/process/setUserCookie 호출됨.');

  // 쿠키 설정
  res.cookie('user', {
    id: 'mike',
    name: '소녀시대',
    authorized: true
  });

  // redirect 로 응답
  res.redirect('/process/showCookie');
});

app.get('/process/product', function(req, res) {
  console.log('/process/product 호출됨.');

  if (req.session.user) {
    res.redirect('/public/product.html');
  } else {
    res.redirect('/public/login2.html');
  }
})

app.post('/process/photo', upload.any('photo'), function(req, res) {
  console.log('/process/photo 호출됨.');

  var files = req.files;

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

  if (Array.isArray(files)) { // 배열에 들어 있는 경우
    console.log('배열에 들어 있는 파일 개수 : %d', files.length);
    for (var index = 0; index < files.length; index++) {
      originalname = files[index].originalname;
      name = files[index].name;
      mimetype = files[index].mimetype;
      size = files[index].mimetype;
    }
  } else { // 배열에 들어가 있지 않은 경우 (현재 설정에서는 해당 없음)
    console.log('파일 개수 : 1');

    originalname = files[index].originalname;
    name = files[index].name;
    mimetype = files[index].mimetype;
    size = files[index].size;
  }

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

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

// 모든 router 처리 끝난 후 404 오류 페이지 처리

/*var errorHandler = expressErrorHandler({
  static: {
    '404': './public/404.html'
  }
});*/

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

app.all('*', function(req, res) {
  res.send(404, '<h1>ERROR - 페이지를 찾을 수 없습니다.</h1>');
});

app.use(function(req, res, next) {
  console.log('첫 번째 미들웨어에서 요청을 처리함.');

  var userAgent = req.header('User-Agent');
  var paramName = req.param('name');

  res.writeHead('200', {'Content-Type': 'text/html;charset=utf8'});
  res.write('<h1>Express 서버에서 응답한 결과입니다.</h1>');
  res.write('<div><p>User-Agent : ' + userAgent + '</p></div>');
  res.write('<div><p>Param name : ' + paramName + '</p></div>');
  res.end();
});


http.createServer(app).listen(3000, function() {
  console.log('Express 서버가 3000번 포트에서 시작됨.');
});
728x90