24.06.05 10:54 작성
·
99
0
실시간 채팅방 강좌 코드를 작성하여 작동 시켜 본 결과 메시지 전송 까지는 잘 되는 것을 확인 하였는데 GIF 업로드 시 다음 그림과 같은 현상이 발생하고 있습니다
그림 하단에 표시한 부분 처럼 처음에 GIF 올리기를 하면 그림이 보이지 않다가 새로 고침을 하면 위의 다른 GIF 처럼 잘 보이긴 하는데 무슨 문제 일까요?
참고로 관련 코드를 같이 올립니다
chat.html
{% extends 'layout.html' %}
{% block content %}
<h1>{{title}}</h1>
<a href="/" id="exit-btn">방 나가기</a>
<fieldset>
<legend>채팅 내용</legend>
<div id="chat-list">
{% for chat in chats %}
{% if chat.user === user %}
<div class="mine" style="color: {{chat.user}}">
<div>{{chat.user}}</div>
{% if chat.gif %}}
<img src="/gif/{{chat.gif}}">
{% else %}
<div>{{chat.chat}}</div>
{% endif %}
</div>
{% elif chat.user === 'system' %}
<div class="system">
<div>{{chat.chat}}</div>
</div>
{% else %}
<div class="other" style="color: {{chat.user}}">
<div>{{chat.user}}</div>
{% if chat.gif %}
<img src="/gif/{{chat.gif}}">
{% else %}
<div>{{chat.chat}}</div>
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
</fieldset>
<form action="/chat" id="chat-form" method="post" enctype="multipart/form-data">
<label for="gif">GIF 올리기</label>
<input type="file" id="gif" name="gif" accept="image/gif">
<input type="text" id="chat" name="chat">
<button type="submit">전송</button>
</form>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io.connect('http://localhost:8005/chat', {
path: '/socket.io',
});
socket.emit('join', new URL(location).pathname.split('/').at(-1));
socket.on('join', function (data) {
const div = document.createElement('div');
div.classList.add('system');
const chat = document.createElement('div');
div.textContent = data.chat;
div.appendChild(chat);
document.querySelector('#chat-list').appendChild(div);
});
socket.on('exit', function (data) {
const div = document.createElement('div');
div.classList.add('system');
const chat = document.createElement('div');
div.textContent = data.chat;
div.appendChild(chat);
document.querySelector('#chat-list').appendChild(div);
});
socket.on('chat', function (data) {
const div = document.createElement('div');
if (data.user === '{{user}}') {
div.classList.add('mine');
} else {
div.classList.add('other');
}
const name = document.createElement('div');
name.textContent = data.user;
div.appendChild(name);
if (data.chat){
const chat = document.createElement('div');
chat.textContent = data.chat;
div.appendChild(chat);
} else {
const gif = document.createElement('img');
gif.sr = '/gif/' + data.gif;
div.appendChild(gif);
}
div.style.color = data.user;
document.querySelector('#chat-list').appendChild(div);
});
document.querySelector('#chat-form').addEventListener('submit', function (e) {
e.preventDefault();
if (e.target.chat.value) {
axios.post('/room/{{room._id}}/chat', {
chat: this.chat.value,
})
.then( () => {
e.target.chat.value = '';
})
.catch( (err) => {
console.error(err);
});
}
});
document.querySelector('#gif').addEventListener('change', function (e) {
console.log('******',e.target.files);
const formData = new FormData();
formData.append('gif', e.target.files[0]);
axios.post('/room/{{room._id}}/gif', formData)
.then( () => {
e.target.file = null;
})
.catch( (err) => {
console.error(err);
});
});
</script>
{% endblock %}
routes/index.js
const express = require('express');
const { renderMain, renderRoom, createRoom, enterRoom, removeRoom, sendChat, sendGif } = require('../controllers');
const multer = require('multer');
const fs = require('fs');
const path = require('path');
const router = express.Router();
router.get('/', renderMain);
router.get('/room', renderRoom);
router.post('/room', createRoom);
router.get('/room/:id', enterRoom);
router.delete('/room/:id', removeRoom);
router.post('/room/:id/chat', sendChat);
try {fs.readdirSync('uploads');
} catch (err) {
console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.');
fs.mkdirSync('uploads');
}
const upload = multer({
storage: multer.diskStorage({
destination(req, file, done) {
done(null, 'uploads/');
},
filename(req, file, done ) {
const ext = path.extname(file.originalname);
done(null, path.basename(file.originalname, ext) + Date.now() + ext);
},
}),
limits: {fileSize: 5 * 1024 *1024 },
})
router.post('/room/:id/gif', upload.single('gif'), sendGif);
module.exports = router;
controllers/index.js
const Room = require('../schemas/room');
const Chat = require('../schemas/chat');
const { removeRoom: removeRoomService } = require('../services');
exports.renderMain = async ( req, res, next ) => {
try{
const rooms = await Room.find({});
res.render('main', {rooms, title: 'GIF 채팅방'});
} catch (error) {
console.error(error);
next(error);
}
};
exports.renderRoom = ( req, res, next ) => {
res.render('room', { title: 'GIF 채팅방 생성'});
};
exports.createRoom = async ( req, res, next ) => {
try{
const newRoom = await Room.create({
title: req.body.title,
max: req.body.max,
owner: req.session.color,
password: req.body.password, //session data 에서 옮
});
const io = req.app.get('io');
io.of('/room').emit('newRoom', newRoom);
// 방에 들어가는 부분
if (req.body.password ) {
res.redirect(`/room/${newRoom._id}?password=${req.body.password}`);
} else {
res.redirect(`/room/${newRoom._id}`);
}
} catch (error) {
console.error(error);
next(error);
}
};
exports.enterRoom = async( req, res, next ) => {
try{
const room = await Room.findOne({_id: req.params.id});
if (!room){
return res.redirect('/?error=존재하지 않는 방입니다.');
}
if (room.password && room.password !== req.query.password ){
return res.redirect('/?error=비밀번호가 틀렸습니다.');
}
const io = req.app.get('io');
const { rooms } = io.of('/chat').adapter;
if (room.max <= rooms.get(req.params.id)?.size) {
return res.redirect('/?error=허용 인원을 초과하였습니다.');
}
const chats = await Chat.find({room: room._id }).sort('createdAt');
res.render('chat', { title: 'GIF 채팅방 생성', chats , room, user: req.session.color });
} catch (error) {
console.error(error);
next(error);
}
};
exports.removeRoom = async ( req, res, next ) => {
try {
await removeRoomService(req.params.id );
res.send('ok');
setTimeout(() => {
req.app.get('io').of('/room').emit('removeRoom', req.params.id);
}, 2000)
} catch (error) {
console.error(error);
next(error);
}
};
exports.sendChat = async (req, res, next ) =>{
try {
const chat = await Chat.create({
room: req.params.id,
user: req.session.color,
chat: req.body.chat,
});
req.app.get('io').of('/chat').to(req.params.id).emit('chat', chat);
res.send('ok');
} catch( error ){
console.error(error);
next(error);
}
}
exports.sendGif = async (req, res, next ) => {
try {
const chat = await Chat.create({
room : req.params.id,
user: req.session.color,
gif: req.file.filename,
})
setTimeout(() => {
req.app.get('io').of('/chat').to(req.params.id).emit('chat',chat);
}, 1000);
res.send('ok');
} catch (error) {
console.error(error);
next(error);
}
}
[제로초 강좌 질문 필독 사항입니다]
질문에는 여러분에게 도움이 되는 질문과 도움이 되지 않는 질문이 있습니다.
도움이 되는 질문을 하는 방법을 알려드립니다.
https://www.youtube.com/watch?v=PUKOWrOuC0c
0. 숫자 0부터 시작한 이유는 1보다 더 중요한 것이기 때문입니다. 에러가 났을 때 해결을 하는 게 중요한 게 아닙니다. 왜 여러분은 해결을 못 하고 저는 해결을 하는지, 어디서 힌트를 얻은 것이고 어떻게 해결한 건지 그걸 알아가셔야 합니다. 그렇지 못한 질문은 무의미한 질문입니다.
1. 에러 메시지를 올리기 전에 반드시 스스로 번역을 해야 합니다. 번역기 요즘 잘 되어 있습니다. 에러 메시지가 에러 해결 단서의 90%를 차지합니다. 한글로 번역만 해도 대부분 풀립니다. 그냥 에러메시지를 올리고(심지어 안 올리는 분도 있습니다. 저는 독심술사가 아닙니다) 해결해달라고 하시면 아무런 도움이 안 됩니다.
2. 에러 메시지를 잘라서 올리지 않아야 합니다. 입문자일수록 에러메시지에서 어떤 부분이 가장 중요한 부분인지 모르실 겁니다. 그러니 통째로 올리셔야 합니다.
3. 코드도 같이 올려주세요. 다만 코드 전체를 다 올리거나, 깃헙 주소만 띡 던지지는 마세요. 여러분이 "가장" 의심스럽다고 생각하는 코드를 올려주세요.
4. 이 강좌를 바탕으로 여러분이 응용을 해보다가 막히는 부분, 여러 개의 선택지 중에서 조언이 필요한 부분, 제 경험이 궁금한 부분에 대한 질문은 대환영입니다. 다만 여러분의 회사 일은 질문하지 마세요.
5. 강좌 하나 끝날 때마다 남의 질문들을 읽어보세요. 여러분이 곧 만나게 될 에러들입니다.
6. 위에 적은 내용을 명심하지 않으시면 백날 강좌를 봐도(제 강좌가 아니더라도) 실력이 늘지 않고 그냥 코딩쇼 관람 및 한컴타자연습을 한 셈이 될 겁니다.
답변 1
0
2024. 06. 05. 12:54
저거 네트워크 탭 열어서 websocket 요청 클릭해서 메시지 확인해봐야 할 것 같습니다.
/gif/ + data.gif 경로가 올바른 경로가 맞는지(express.static이 가리키는) 확인이 필요합니다.
2024. 06. 05. 17:25
아아 거기였군요. 실시간으로 gif 표시하는 건 자바스크립트(오타) 부분이고, 새로고침 시 초기 화면 그리는 건 nunjucks가 하고 있어서 그렇습니다.
2024. 06. 05. 15:58
문제 해결 되었습니다
강사님 말씀하신 부분 참고해서 찾아보니 chat.html 부분에 "gif.src" 를 "gif.sr"로 오타가 있었습니다
수정하니 올바로 작동 하였습니다
그런데 질문이 하나 있습니다
gif.src에 데이터가 잘못 들어가 GIF가 바로 안 보인 것인데 새로 고침을 하면 보이는 것은 어떤 이유 일까요?