티스토리 게시글 방문 알림 기능 만들어보기 ( Node js, Express, Discord )

2023. 12. 9. 02:26일반

 

발단

 

우테코 프리코스가 끝나고 나는 심심할 때면 티스토리 방문 통계를 보곤 했다. 방문 통계에는 유입 경로가 나와 있는데, 내가 우테코 증빙자료로 첨부해 놓은 주소와 같은 경로로 들어온 흔적이 보이면 우테코님들께서 다녀가신 것 같은 기분이 들었기 때문이다.

 

친구는 내가 이렇게 시도 때도 없이 불멍 때리듯이 방문 통계로 통멍을 때리는 것을 보고, 그럴거면 차라리 글에 방문자가 생길 때마다 알림을 보내는 일종의 게시글 현관종(?) 기능을 만들어보는건 어떠겠냐 물었고, 흥미가 생긴 나는 기말고사가 끝나기만을 기다렸다 마지막 시험이 끝나자마자 만들어봤다.

 

 

기능 구조는 아래와 같다.

  1. 서버를 하나 만들고 배포한다.
  2. 서버에 이미지 파일을 호스팅한다.
  3. 서버 코드에 사용자 정의 미들웨어를 추가하여 나의 로컬 폴더의 이미지에 접근 가능하도록 함과 동시에 접근을 감지하는 코드를 구현한다.
  4. 티스토리 게시글에 html로 이미지 태그의 src에 나의 서버 주소의 이미지 파일 경로를 직접 입력하여 이미지를 출력한다.
  5. 디스코드의 웹훅기능을 이용해 이미지 파일 주소에 접근하면 디스코드로 나에게 메시지를 보내도록 로직을 작성한다.

이렇게 되면 방문자(클라이언트)가 내가 게시한 글을 열람하면 글에 첨부된 이미지를 방문자(클라이언트)가 서버에 요청하게 되고, 요청을 서버에서 감지하고 나에게 디스코드로 알림을 보내주게 된다.

 

 

서버 생성 및 배포 - CloudType

 

서버 코드를 직접 작성한 뒤 깃허브에 게시하고 CloudType에서 해당 repository를 선택하여 배포해도 되지만,

CloudType에서 깃허브를 연동하고, 직접 템플릿을 선택하여 프로젝트와 프로젝트 리포지토리를 생성하는 방법도 있다.

 

나는 후자의 방식을 택했고, Node js 템플릿을 선택하여 생성했다. 생성 과정은 매우 간단하여 별도의 설명이 필요하지 않다고 생각되어 생략하겠습니다.

 

템플릿을 선택하고 원하는 옵션들을 선택한 뒤 프로젝트를 생성하면, 생성과 동시에 default로 존재하는 코드들로 바로 배포되는 것을 볼 수있다.

 

그리고 GitHub에 가면 생성된 Repository도 볼 수 있다.

 

 

GitHub Action CI/CD

서버의 코드가 수정 될 때마다 수동으로 빌드하고 다시 배포하는 것은 상당히 수고스러운 작업이다. 그래서 나는 서버를 생성하고 가장 먼저 GitHub Action CI/CD를 설정했다.

 

CI는 빌드와 테스트를 자동화하는 것을 뜻하고, CD 배포 준비가 된(빌드 된) 코드를 자동으로 서버에 배포하는 작업을 자동화하는 것을 뜻한다.

 

CloudType으로 배포한 서버의 CI/CD를 설정하는 방법은 아래 영상에 매우 친절하게 나와있으니, 영상을 보고 따라하면 되겠다. 아래 영상을 따라 CI/CD 설정까지 완료했다면, 이제 변경 내용을 커밋하고 원격 저장소에 Push하면 자동으로 CloudType 변경 사항을 반영된 서버를 재배포 해주는 것을 볼 수 있을 것이다.

 

 

방문자 알림 기능 구현

이제 서버를 만들었고 배포까지 자동화했으니, 코드만 작성하면 되겠다. Clone하여 로컬 개발 환경에서 프로젝트를 열어주자.

 

ctrl + shift + p , >clone

 

 

 

복제한 프로젝트의 폴더 구조는 아래와 같다. 주목해야 될 폴더 및 파일 public, routes/index.js, app.js 이다.

public 폴더에는 호스팅할 이미지 파일을 저장할 것이고, routes/index.js 는 실질적인 기능 코드와 자원 요청 코드들이 작성될 것이다.

 

 

 

아래는 구현된 router/index.js 파일이다. 간단히 요약하자면,

1. 나의 로컬 public 폴더에 존재하는 이미지 파일을 클라이언트가 요청할 수 있도록 experss의 use함수를 사용해 사용자 정의 미들웨어를 추가하여 public 폴더에 접근 가능하도록 하였다.

//사용자 정의 미들웨어 추가 - 1
app.use(express.static('public'));

 

 

2. 현재 내가 호스팅 하고자 하는 book-logo.png 이미지 파일의 경로는 'public/images/book-logo.png' 이고, 클라이언트는 '내 서버 주소/images/book-logo.png' 에 접근하면 이미지 파일을 요청할 수 있을 것이다. 그렇기 때문에 사용자의 이미지 요청을 감지하여 알림 기능을 수행하기 위해 또 하나의 사용자 정의 미들웨어를 추가해준다.

 

이때 미들웨어는 1번에서 추가한 미들웨어보다 윗단에 추가해야지 정상적으로 클라이언트의 요청을 감지할 수 있다. 

여기까지 했다면 사용자가 이미지를 요청할 때마다 console에 이미지를 요청하는 클라이언트의 ip가 출력되는 것을 볼 수있다.

 

클라이언트의 ip를 수집하는 것이 보안상 문제가 될까 걱정했지만, 수집되는 것은 단순한 public ip이기 때문에 클라이언트의 실제 거주지와 같은 정보를 얻는 것이 아니라 괜찮을 것 같다 판단하여 추가하였다.

app.use("/images/book-logo.png", function (req, res, next) {
  var ip = req.headers["x-forwarded-for"] || req.ip || req.connection.remoteAddress;
  console.log("ip : ", ip); // 사용자의 IP 주소를 로그에 기록합니다.
  next();
});

 

3. 이제 2번의 미들웨어를 추가하는 로직의 function 안에 디스코드 웹훅을 이용하여 내 채널로 알림을 보내는 로직을 작성해주자. 

var express = require("express");
var router = express.Router();
var axios = require("axios");
var app = express();

// 사용자 정의 미들웨어 추가 - 2.
app.use("/images/book-logo.png", function (req, res, next) {
  var ip = req.headers["x-forwarded-for"] || req.ip || req.connection.remoteAddress;
  console.log("ip : ", ip); // 사용자의 IP 주소를 로그에 기록합니다.

  var webhookUrl = "디스코드 웹훅 URL";

  // 디스코드에 보낼 메시지
  var message = {
    content: "블로그 접속 감지: IP 주소 - " + ip,
  };

  // 디스코드 웹훅으로 메시지를 보냅니다.
  axios.post(webhookUrl, message)
    .then(() => console.log("메시지가 디스코드로 전송됨"))
    .catch((err) => console.error("디스코드로 메시지를 보내는 데 실패함:", err));

  next();
});

//사용자 정의 미들웨어 추가 - 1
app.use(express.static('public'));

// 기존 라우터 설정
router.get("/", function (req, res, next) {
  res.render("index.html");
});

app.use('/', router);

module.exports = app;

 

 

디스코드 웹훅

이제 마지막으로 디스코드 웹훅을 생성한 뒤 생성된 웹훅의 url을 아래 부분에 넣어주면 된다.

var webhookUrl = "디스코드 웹훅 URL";

 

디스코드 웹 훅을 생성하는 방법은 정말 간단하다. 먼저 아무 채널이나 만든 뒤, 채널 편집을 클릭해주자.

 

그럼 아래와 같이 연동 섹션을 클릭하면, 웹후크가 보일 것이다. [웹후크 만들기] 버튼을 클릭해주자.

 

[웹후크 만들기]를 클릭했다면 곧바로 생성된 웹후크를 볼 수 있을 것이다. 이제 생성된 웹후크의 URL을

[웹후크 URL 복사] 버튼을 클릭하여 복사 한뒤, 코드로 돌아가 입력해주면 되겠다.

 

 

티스토리 게시글에 호스팅 된 이미지 파일 첨부

위에서 말했듯이 이미지 파일을 서버에서 요청할 것이기 때문에, html로 변경한 뒤 img 태그의 src 속성에 직접 주소를 입력해줄 것이다. 먼저 작성중인 게시글 위 툴바에 기본모드를 클릭하여 HTML로 바꿔주자.

 

 

 

 

 

HTML로 바꿔 주었다면 이미지를 넣고 싶은 영역에 아래와 같이 코드를 작성하면 된다.

<img src="서버주소/public을_제외한_로컬_이미지_경로/image.png">

 

나는 추가적으로 이미지를 가운데로 정렬하고 싶어서 div 태그로 감싼뒤 style = "text-align: center" 속성을 주었다.

 

이렇게 입력해주고 다시 기본 모드로 돌아와주면 이미지가 정상적으로 출력되는 것을 볼 수 있을 것이다.

 

 

이제 이대로 글을 올려주면 ~~ 이 게시글을 읽은 사용자는 내 서버에 이미지를 호출하게 되고, 이를 감지한 내 서버는 디스코드로 클라이언트의 방문을 알려주게 된다.

 

 

 

 

느낀점

막상 시험이 끝나고 나니 우테코 1차 합격 발표까지 4일밖에 남지 않아서, 본래 취지였던 우테코님들의 방문을 엿보기에는 글렀지만 만들고 나니 생각보다 얻게 된 것들이 많았다.

 

그 예로, node js 서버를 배포하는 법, GitHub Action CI/CD를 설정하는 법, 그리고 디스코드 웹훅 활용까지 내가 실제로 사용할 뭔가를 직접 만든다고 생각하니 만약 공부 자체가 목적이었다면 지루했을 수 있었을 법한 내용들도 재미있게 느껴졌고 몰입해서 학습할 수 있었다.

 

 

추가적인 목표

이번에 만들게 된 기능을 바탕으로 조금 더 나아가서 방문자의 체류 시간 등과 같은 좀 더 생산성 있는 정보까지 수집해보는 것이 다음 목표이다.