2022. 1. 10. 14:42ㆍ프로그래밍/개인프로젝트
POMOTODO를 만들면서 작성한 코드를 복습하기 위해 작성하는 글입니다.
0. 준비사항
00시 00분이 되면 DB에 데이터를 새로 생성하고 브라우저에 출력해주는 화면도 초기화되도록 로직을 짜 놨다
1. 문제 인식
로컬에서는 잘 작동하는데 AWS EC2로 구축한 도메인으로 접속했을 때는 어제 정보가 출력되는 이슈가 있었다.
'업데이트가 늦나 보다..'라고 생각하고 새벽 2시에 잤고, 일어나서 확인하니 잘 작동해서 별로 대수롭지 않게 넘어갔다.
이슈 체크하려고 23시 59분을 기다렸고, 동일한 문제가 며칠 동안 발생하는 걸 인지하고 이건 코드 문제인 것 같아서 코드를 하나하나 뜯어봤다
2. 문제 원인 분석
코드에는 별 문제가 없다고 판단했고, 그럼 어디가 문제인지 생각나는 대로 공책에 적다 보니 시간을 가져오는 new Date() 쪽에 문제가 있다고 생각했다.
결론부터 말하자면, header.js(자바스크립트)에서 사용하는 new Date는 접속한 컴퓨터의 날짜나 시간을 기준으로 가져오고,
server.js(서버)에서 사용하는 new Date는 서버 컴퓨터의 날짜/시간을 가져온다.
로컬에서 실행할 때는 내가 사용중인 컴퓨터의 시간을 기준으로 가져오기 때문에 잘 작동했고,
AWS 환경에서 실행할 때는 서버 컴퓨터가 UTC기준으로 맞춰져 있었기 때문에 로컬과 서버 컴퓨터간 오차가 발생했던 것이다.
3. 문제 해결
단순 서버 컴퓨터의 timezone을 변경해주면 쉽게 해결할 수 있다고 생각했으나,
한국 유저만 고려하고 로직을 짠다면 추후에 외국인 유저 유입 시 또 변경해야 한다고 생각했고
header.js(즉, 접속 컴퓨터)의 시간을 서버에서 받아서 처리하도록 구현하려고 했다.
시도한 방법을 시간 순서대로 정렬해서 어떤 문제점이 있었고 어떻게 처리했는지 정리하려고 한다.
1. jQuery ajax를 통해
홈('/')으로 get요청 시 - 서버로 '날짜' 데이터를 전송하고 - 서버에선 받은 '날짜'데이터를 기반으로 DB에 데이터를 생성해준다.
-> 문제점
- 홈으로 get 요청하면 회원/비회원 서로 다른 화면을 출력해주도록 구현했는데
회원의 경우 로그인할 때 passport미들웨어를 사용하기 때문에 ajax를 통한 데이터를 받을 수 없었다.
(req.어쩌구저쩌구 실행 시 passport의 정보를 사용할 수 있었기 때문에)
2. 그래서 다른 방법을 시도해봤다
기존에는 홈으로 get요청 시 데이터를 생성하고 출력해주는 모든 기능을 한 번에 수행했는데
데이터를 생성, 출력을 나눠주기로 했다.
post요청 시 데이터를 생성해주고,
get요청 시 데이터를 출력해주도록
post요청 시 데이터를 생성
main.js에서는 00시 00분이 되면 홈으로 post 요청을 한다,
전송하는 데이터는'유저 아이디'와 '날짜'
서버에서는 post요청을 받으면 데이터를 기반으로 DB에서 조회해보고 없다면 새로운 데이터를 생성해주도록 한다.
get요청 시 데이터를 출력
'/'으로 get요청을 하면 '유저 아이디'를 기반으로 데이터를 찾고(findOne()이 아닌 find()를 써서 배열로 불러오게 한다),
배열의 마지막 값을 출력해주도록 한다
-> 날짜가 바뀌면 post요청으로 새로운 데이터가 생성되고, 그 데이터가 배열의 마지막 값이 되기 때문에
get요청 시 최근 데이터를 출력해주도록 했고,
00시 00분에 접속 중인 유저는 데이터가 꼬이기 때문에 홈으로 리다이렉트 해주도록 했다.
(post요청과 리다이렉트를 같이 구현하니깐 리다이렉트가 완료되고 나서 어제 데이터를 출력해줘서
00시 00분에는 post요청, 00시 01분에는 리다이렉트 하는 식으로 구현했다)
서버의 날짜를 사용하는 다른 코드가 있는지 확인한 결과
1. 포모도로 타이머, 투두 리스트, 낫 투두 리스트를 입력할 때
2. record페이지로 get 요청할 때
두 곳에서 사용하는 걸 확인했고 각각 처리해줬다
1. 포모도로 타이머, 투두 리스트, 낫 투두 리스트를 입력할 때
애초에 main.js에서 ajax로 post 요청하는 로직이어서 ajax요청 시 날짜를 데이터로 넘겨주고
서버에서는 '넘어온 날짜 데이터'를 조건에 넣어서 데이터를 업데이트해주도록 했다
2. record페이지로 get 요청할 때
record페이지도 회원/비회원을 구분하는 미들웨어를 사용하기 때문에 유저의 id만 조회해서 배열의 마지막 값을 출력해주도록 했다
코드 첨부
server.js
//server.js
// 홈페이지 post요청시 데이터를 생성해줄 코드
app.post('/',function(req, res){
// 서버에 날짜에 따른 데이터 생성, post요청은 홈으로 리다이렉트 할 때마다 한다 - 클라이언트의 시간이 00시 00분이면 리다이렉트 시키기 때문에 날짜변경되면 데이터 생성하도록
console.log(req.body.id) // ajax전달받는 데이터 id
console.log(req.body.yyyymmdd) // ajax 전달받는 날짜
if(req.body.id !== 'log in'){
db.collection('pomodoro').findOne({id: req.body.id, 'yyyymmdd' : req.body.yyyymmdd}, function(err, pomodoroResult){
if(pomodoroResult==null){ // 없으면 빈값의 데이터 생성
db.collection('pomodoro').insertOne({ 'id' : req.body.id, 'yyyymmdd' : req.body.yyyymmdd ,'contentHTML' : '' }, function(err, result){
});
}
})
db.collection('todolist').findOne({id: req.body.id, 'yyyymmdd' : req.body.yyyymmdd}, function(err, todolistResult){
if(todolistResult==null){
db.collection('todolist').insertOne({ 'id' : req.body.id, 'yyyymmdd' : req.body.yyyymmdd ,'todoListHTML' : '' }, function(err, result){
});
}
})
db.collection('not-todolist').findOne({id: req.body.id, 'yyyymmdd' : req.body.yyyymmdd}, function(err, nottodolistResult){
if(nottodolistResult==null){
db.collection('not-todolist').insertOne({ 'id' : req.body.id, 'yyyymmdd' : req.body.yyyymmdd ,'notTodoListHTML' : '' }, function(err, result){
});
}
})
res.status(200).send({ message : '리다이렉트-데이터생성??'});
}
})
// 홈페이지 get요청시 출력해줄 코드
app.get('/',homeLoginCheck,function(req, res){
//서버에서 단순 검색 및 출력담당
db.collection('pomodoro').find({id : req.user.id}).toArray(function(err,pomodoroResult){
let a = pomodoroResult.length-1;
// console.log(a) // 마지막 배열 인덱스 == a
// console.log(pomodoroResult[a]) // 마지막 배열 출력
// console.log(pomodoroResult[a].contentHTML.length) // 배열 마지막값 출력
pomoResult = pomodoroResult[a].contentHTML;
db.collection('todolist').find({id : req.user.id}).toArray(function(err,todolistResult){
let b = todolistResult.length-1;
todoResult = todolistResult[b].todoListHTML;
db.collection('not-todolist').find({id : req.user.id}).toArray(function(err,nottodolistResult){
let c = nottodolistResult.length-1;
notTodoResult = nottodolistResult[c].notTodoListHTML;
res.render('POMOTODO.ejs', { posts : req.user.id, pomodoroRecord : pomoResult, todoListRecord : todoResult, notTodoListRecord : notTodoResult});
})
})
})
});
//pomodoro, todolist, not-todolist 업데이트
// Pomodoro 기록 업데이트
app.post('/insertPomodoro', function(req, res){
if(req.user !== undefined){ //로그인 했을때만 db에 저장하도록 하는 코드
db.collection('pomodoro').updateOne({id : req.user.id, yyyymmdd : req.body.yyyymmdd}, { $set : req.body }, function(err, result){
console.log('뽀모도로 업데이트')
res.status(200).send({ message : '뽀모 업데이트 성공했습니다'});
})
}else{
console.log('로그인을 해주세요');
res.status(200).send({ message : '로그인을 해주세요'});
}
})
//투두리스트 업데이트
app.post('/insertTodoList', function(req, res){
if(req.user !== undefined){
db.collection('todolist').updateOne({id : req.user.id, yyyymmdd : req.body.yyyymmdd}, { $set : req.body }, function(err, result){
console.log('투두리스트 업데이트')
res.status(200).send({ message : '투두 업데이트 성공했습니다'});
})
}else{
console.log('로그인을 해주세요');
res.status(200).send({ message : '로그인을 해주세요'});
}
})
//낫투두리스트 업데이트
app.post('/insertNotTodoList', function(req, res){
if(req.user !== undefined){
db.collection('not-todolist').updateOne({id : req.user.id, yyyymmdd : req.body.yyyymmdd}, { $set : req.body }, function(err, result){
console.log('낫투두리스트 업데이트')
res.status(200).send({ message : '낫투두 업데이트 성공했습니다'});
})
}else{
console.log('로그인을 해주세요');
res.status(200).send({ message : '로그인을 해주세요'});
}
})
// record페이지 접속
app.get('/record',recordLoginCheck,function(req, res){
if(req.user.id !== 'log in'){
db.collection('pomodoro').find({id : req.user.id}).toArray(function(err,pomodoroResult){
let a = pomodoroResult.length-1;
pomoRecordRes = pomodoroResult[a].contentHTML;
db.collection('todolist').find({id : req.user.id}).toArray(function(err,todolistResult){
let b = todolistResult.length-1;
todoRecordRes = todolistResult[b].todoListHTML;
db.collection('not-todolist').find({id : req.user.id}).toArray(function(err,nottodolistResult){
let c = nottodolistResult.length-1;
notTodoRecordRes = nottodolistResult[c].notTodoListHTML;
res.render('record.ejs', { 'posts' : req.user.id, 'pomos' : pomoRecordRes, 'todos' : todoRecordRes, 'notTodos' : notTodoRecordRes});
})
})
})
}
});
header.js
let userId = document.querySelector('#modal-button-id-check');
// 홈으로 get요청시 일단 매번 체크해주도록한다
function checkData(){
$.ajax({
method : 'post',
url : '/',
data : {id : userId.innerHTML, yyyymmdd : yyyymmdd()},
success : function() {
console.log('홈 ajax 성공')
},
error : function(xhr, status, error) {
console.log('홈 ajax 실패');
}
})
}
checkData();
// 1분에 한번씩 체크해서 00시 00분, 00시 01분에 checkData를 실행한다
function addStringZero(time){
if(parseInt(time)<10)
return "0"+time;
else
return time;
}
function setClock(){
let dateObject = new Date();
let year = dateObject.getFullYear();
let month = dateObject.getMonth()+1;
let date = dateObject.getDate();
let hour = addStringZero(dateObject.getHours());
let min = addStringZero(dateObject.getMinutes());
document.getElementById("POMOTODO__clock").innerHTML = year + ". " + month + ". " + date + " . " + hour+ " : " + min ;
if(hour == '00' && min == '00'){
checkData();
}
if(hour == '00' && min == '01'){
window.location.href = 'https://pomotodo.kr/';
console.log('recirect!!');
}
}
window.onload = function(){
setClock();
setInterval(setClock,1000);
}
문제가 되는 곳이 눈에 잘 안 보여서 원인을 찾아내는데 너무 고생했고 너무 답답했다
하지만 이슈를 해결하면서 로컬 컴퓨터와 서버 컴퓨터의 관계, get요청과 post요청의 차이점,
미들웨어의 유무에 따라 요청 값을 다르게 받을 수 도 있다 라는 개념을 익힐 수 있었다.
'프로그래밍 > 개인프로젝트' 카테고리의 다른 글
POMOTODO : DB설계 시각화 (0) | 2022.01.11 |
---|---|
POMOTODO : issue (502 bad gateway) (0) | 2022.01.11 |
POMOTODO : ubuntu 포트포워딩,도메인연결(AWS) (0) | 2022.01.09 |
POMOTODO : issue (db조회 및 출력시 병목현상) (0) | 2022.01.09 |
POMOTODO : 이슈 (setInterval inactive issue) (0) | 2022.01.08 |