글로벌 사진 사이트 구축하기

이재홍 http://www.pyrasis.com 2014.03.24 ~ 2014.06.30

웹 서버 및 사이트 내용 둘러보기

웹 서버의 내용을 살펴보겠습니다. 먼저 Node.js의 express 모듈로 80번 포트에 웹 서버를 실행합니다.

  • multer 모듈은 multipart/form-data를 처리하는 모듈입니다.
  • app.use 함수로 multer 모듈을 활성화 합니다. 그리고 업로드된 파일은 uploads 디렉터리에 저장합니다.
var express = require('express')
  , multer = require('multer')
...
  , http = require('http')
  , app = express()
  , server = http.createServer(app)
...
app.use(multer({ dest: './uploads/' }));
...
server.listen(80);

서버 기본 설정 및 정의입니다.

  • 이미지 저장용 S3 버킷 이름, SQS 큐 URL, RDS 엔드포인트 주소(MySQL)와 연결 설정은 여러분들이 생성한 AWS 리소스의 정보를 입력합니다.
  • 파일 정보의 테이블을 정의하고, 테이블을 생성합니다.
var s3Bucket = 'examplephoto.image';
var sqsQueueUrl = 'https://sqs.ap-northeast-1.amazonaws.com/232075047203/ExamplePhotoQueue';
var rdsEndpoint = {
  host: 'examplephoto.cnlconsezo7y.ap-northeast-1.rds.amazonaws.com',
  port: 3306
};

// MySQL DB 이름, 계정, 암호
var sequelize = new Sequelize('examplephoto', 'admin', 'adminpassword', {
  host: rdsEndpoint.host,
  port: rdsEndpoint.port
});

// MySQL DB 테이블 정의
var Photo = sequelize.define('Photo', {
  filename: { type: Sequelize.STRING, allowNull: false, unique: true }
});

// MySQL DB 테이블 생성
sequelize.sync();

/, /index.html에 GET 메서드로 접속했을 때 index.html 파일을 출력합니다.

app.get(['/', '/index.html'], function (req, res) {
  fs.readFile('./index.html', function (err, data) {
    res.contentType('text/html');
    res.send(data);
  });
});

/images에 GET 메서드로 접속했을 때 이미지 목록을 출력합니다.

  • Sequelize 모듈로 MySQL에서 이미지 파일 목록을 가져와서 배열 형태로 출력합니다.
  • CloudFront에서 이미지 목록을 캐시하지 않도록 HTTP 헤더에 Cache-Control을 설정합니다. 이 부분을 설정하지 않으면 매번 고정된 내용을 가져오게 되므로 주의합니다.
// 이미지 목록 출력
app.get('/images', function (req, res) {
  Photo.findAll().success(function (photoes) {
    var data = [];
    photoes.map(function (photo) { return photo.values; }).forEach(function (e) {
      data.push(e.filename);
    });

    res.header('Cache-Control', 'max-age=0, s-maxage=0, public');
    res.send(data);
  });
});

/images에 POST 메서드로 이미지(사진) 파일을 받습니다.

  • AWS API로 이미지 파일을 S3 버킷에 저장합니다. 파일의 Content Type을 얻을 때 mime 모듈을 사용합니다.
  • AWS API로 이미지 파일 이름을 SQS 메시지로 보냅니다.
// 웹 브라우저에서 이미지 받기
app.post('/images', function (req, res) {
  fs.readFile(req.files.images.path, function (err, data) {
    var filename = req.files.images.name;
    s3.putObject({
      Bucket: s3Bucket,
      Key: 'original/' + filename,
      Body: data,
      ContentType: mime.lookup(filename)
    }, function (err, data) {
      if (err)
        console.log(err, err.stack);
      else {
        console.log(data);
        
        sqs.sendMessage({
          MessageBody: filename,
          QueueUrl: sqsQueueUrl
        }, function (err, data) {
          if (err)
            console.log(err, err.stack);
          else
            console.log(data);
        });
      }
    });
  });

  res.send();
});

이번에는 웹 브라우저에 표시될 사이트 내용을 살펴보겠습니다. 트래픽을 줄이기 위해 CDN의 jQuery, jQuery UI, jQuery.fileupload, Bootstrap CSS와 JavaScript를 사용합니다.

<head>
  <title>ExamplePhoto</title>
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.5.7/css/jquery.fileupload.min.css">
  
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.5.7/jquery.fileupload.min.js"></script>
</head>

Select files… 버튼을 클릭한 뒤 이미지 파일을 선택하면 /images에 POST 메서드로 이미지 파일을 올립니다.

  • 웹 서버에 파일을 올리는 과정까지만 프로그레스바로 표시합니다.
$('#fileupload').fileupload({
  url: '/images',
  dataType: 'json',
  progressall: function (e, data) {
    var progress = parseInt(data.loaded / data.total * 100, 10);
    $('#progress .progress-bar').css('width', progress + '%');
  }
});

/images에 접속하여 이미지 파일 목록을 가져온 뒤 imagelist에 <img> 태그로 이미지를 표시합니다.

$.getJSON('/images', function (data) {
  $.each(data, function (i, e) {
    var img = $('<img>');
    // 도메인을 구입하였다면 image 서브 도메인 입력
    //img.attr('src', 'http://image.examplephoto.com/resized/' + e)
    // 도메인을 구입하지 않았다면 CloudFront 배포 도메인 입력
    img.attr('src', 'http://d3fo0v5xpnp6x5.cloudfront.net/resized/' + e)
    .attr({'width': '150px', 'height': '150px' })
    .addClass('img-thumbnail');
    $('#imagelist').append(img);
  });
});

저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.