수강이 제한됩니다.
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
AWS typescript 배포 module error 질문 드립니다
강의에서 나온 nodebird를 참고하여 작은 게시판 서비스를 Typescript로 제작하여 AWS ec2에 배포하는 과정에서 import 부분에서 error가 나서 질문들비니다 * error * error. 모듈 부분을 찾을 수 없다는 에러가 검출되고 있습니다 * tsconfig.json * 개발 환경에서는 어떠한 에러도 없었습니다 전에 node-bird를 배포하는 과정에선 에러가 없었는데 이러한 경우에는 어디에서 문제를 찾아볼 수 있을까요..
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
following follower 질문드립니다
선생님 안녕하세요 항상 좋은 강의 가르쳐주셔서 감사합니다 following follower 관련 햇갈리는 부분이 있어서 가르쳐주시면 감사하겠습니다 아래의 user.js 소스코드에서 following follower 코드를 봐주시면요 소스코드 사진에 보라색 박스와 초록색 박스를 표시했습니다 1번째로 드리고 싶은 질문은, 42, 47행의 보라색 User 가 Followings 테이블 역할을 하고 초록색 User가 Followers 테이블 역할을 한다고 이해해도 되는지 질문드리고 싶습니다 2번째로 드리고 싶은 질문은, 43행의 followingId가 보라색 User(Follower테이블 역할)의 기본키인 id를 참고하는 초록색 User(Followings 테이블 역할)가 가진 외래키인지 질문드리고 싶습니다 3번째로 드리고 싶은 질문은, 48행의 followerId가 초록색 User(Followings 테이블 역할)의 기본키인 id를 참고하는 보라색 User(Follower테이블 역할)가 가진 외래키인지 질문드리고 싶습니다 긴 질문을 읽어주셔서 감사합니다
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
Cannot read properties of undefined (reading 'Op') 문제를 도와주시면 감사하겠습니다
선생님 안녕하세요 선생님의 sns 예제 코드에서 app.js에서 아래의 소스코드를 추가해봤습니다 그런데, 구글링을 해봤는데도 에러가 해결이 안되어서 가르쳐주시면 정말 감사하겠습니다 app.js 소스코드입니다 const express = require('express'); const cookieParser = require('cookie-parser'); const morgan = require('morgan'); const path = require('path'); const session = require('express-session'); const nunjucks = require('nunjucks'); const dotenv = require('dotenv'); const passport = require('passport'); dotenv.config(); const pageRouter = require('./routes/page'); const authRouter = require('./routes/auth'); const postRouter = require('./routes/post'); const userRouter = require('./routes/user'); const { sequelize } = require('./models'); const { User,Sequelize:{Op} } = require('./models'); const passportConfig = require('./passport'); const app = express(); passportConfig(); // 패스포트 설정 app.set('port', process.env.PORT || 8001); app.set('view engine', 'html'); nunjucks.configure('views', { express: app, watch: true, }); sequelize.sync({ force: false }) .then(() => { console.log('데이터베이스 연결 성공'); }) .catch((err) => { console.error(err); }); app.use(morgan('dev')); app.use(express.static(path.join(__dirname, 'public'))); app.use('/img', express.static(path.join(__dirname, 'uploads'))); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(session({ resave: false, saveUninitialized: false, secret: process.env.COOKIE_SECRET, cookie: { httpOnly: true, secure: false, }, })); app.use(passport.initialize()); app.use(passport.session()); app.use('/', pageRouter); app.use('/auth', authRouter); app.use('/post', postRouter); app.use('/user', userRouter); User.find({ attribute: ['email', 'nick'], where: {id: {[Op.in]: [1,2]}} }).then((data)=>{ console.log(JSON.stringify(data)) }); app.use((req, res, next) => { const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`); error.status = 404; next(error); }); app.use((err, req, res, next) => { res.locals.message = err.message; res.locals.error = process.env.NODE_ENV !== 'production' ? err : {}; res.status(err.status || 500); res.render('error'); }); app.listen(app.get('port'), () => { console.log(app.get('port'), '번 포트에서 대기중'); }); user.js 소스코드입니다 const Sequelize = require('sequelize'); module.exports = class User extends Sequelize.Model { static init(sequelize) { return super.init({ email: { type: Sequelize.STRING(40), allowNull: true, unique: true, }, nick: { type: Sequelize.STRING(15), allowNull: false, }, password: { type: Sequelize.STRING(100), allowNull: true, }, provider: { type: Sequelize.STRING(10), allowNull: false, defaultValue: 'local', }, snsId: { type: Sequelize.STRING(30), allowNull: true, }, }, { sequelize, timestamps: true, underscored: false, modelName: 'User', tableName: 'users', paranoid: false, charset: 'utf8', collate: 'utf8_general_ci', }); } static associate(db) { db.User.hasMany(db.Post); db.User.belongsToMany(db.User, { foreignKey: 'followingId', as: 'Followers', through: 'Follow', }); db.User.belongsToMany(db.User, { foreignKey: 'followerId', as: 'Followings', through: 'Follow', }); } }; index.js 소스코드입니다 const Sequelize = require('sequelize'); const env = process.env.NODE_ENV || 'development'; const config = require('../config/config')[env]; const User = require('./user'); const Post = require('./post'); const Hashtag = require('./hashtag'); const db = {}; const sequelize = new Sequelize( config.database, config.username, config.password, config, ); db.sequelize = sequelize; db.User = User; db.Post = Post; db.Hashtag = Hashtag; User.init(sequelize); Post.init(sequelize); Hashtag.init(sequelize); User.associate(db); Post.associate(db); Hashtag.associate(db); module.exports = db; 읽어주셔서 감사합니다
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
몽고디비 연결 에러 뜨시는 분 이렇게 해결하세요
아마 최신 노드사용하시는 분은 이런 에러가 뜨실텐데 몽고db 연결하는 url을 const MONGO_URL = `mongodb://${MONGO_ID}:${MONGO_PASSWORD}@127.0.0.1:27017/admin`; 이렇게 바꿔보세요 localhost를 127.0.0.1로 바꾼겁니다
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
몽고디비 연결이 끊겼다는 에러만 나와요 ㅠㅠ
npm list 입니다. 혹시 오타로 인해 제가 작성한 schemas/index.js 파일이 오류가 났을까봐 깃허브에 있는 코드를 복사해서 몽고디비의 아이디, 비밀번호만 변경해봤는데도 연결이 끊겼다는 에러가 나오고 있는데 혹시 버전 문제인지 궁금합니다..
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
12장 웹소켓 데이터베이스 질문입니다.
혹시 데이터베이스를 처음부터 MySQL을 사용해도 될까요? 아니면 몽고DB로 한번 해본 이후 MySQL로 교체해야 하나요? 사실 이게 가장 중요한 질문인데, MySQL로 해도 크게 달라질것 같진 않지만 이해하거나 코드분석하는 것에 어려움이 많을까요?
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
apiLimiter미들웨어가 작동을 안합니다.
보시면 비밀키는 제대로 받고 있습니다. type도 프리미엄인걸 확인할 수 있습니다. exports.freeapiLimiter = RateLimit({ windowMs: 60 * 1000, // 1분 max: 5, delayMs: 0, handler(req, res) { res.status(this.statusCode).json({ code: this.statusCode, // 기본값 429 message: '1분에 5 번만 요청할 수 있습니다.', }); }, }); exports.premiumapiLimiter = RateLimit({ windowMs: 60 * 1000, // 1분 max: 100, delayMs: 0, handler(req, res) { res.status(this.statusCode).json({ code: this.statusCode, // 기본값 429 message: '1분에 100 번만 요청할 수 있습니다.', }); }, }); 미들웨어에 free와 premium 미들웨어를 추가합니다. router.use( async (req, res, next) => { const domain = await Domain.findOne({ where: { host: url.parse(req.get('origin')).host }, }); if(domain.type === 'premiun') { premiumapiLimiter(req, res, next); } else { freeapiLimiter(req, res, next); } }); 도메인 타입에 따라서 해당 미들웨어를 호출합니다 그러나 type이 premium든 free든 항상 free미들웨어가 호출됩니다
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
카카오 아이디에 대해 질문드리고 싶습니다
선생님 안녕하세요 .env 파일에서는 타인의 카카오 아이디로 설정되어 있는데 sns를 실행할 때는 제 카카오 계정으로 로그인 했습니다 혹시 이럴 경우 문제가 있는지 질문드리고 싶습니다
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
관계 쿼리를 정확히 알고싶습니다.
const user = await User.findOne({}); const comments = await user.getComments(); console.log(comments); 책에 나와있는 예제입니다. 여기서 user.getComments(); 이부분에서 getComments() 이게 조회하는 메서드라는 것은 이해했습니다. User과 관계를 맺은 모델인 Comment모델에서 조회하는 것이겠지요. 문제는 그 앞에있는 user. 이 무슨 역할인지 모르겠습니다. const user = await User.findOne({}); 조건에 맞는 객체를 조회했다는 것은 이해했지만 그것과 getComments() 가 무슨 상관관계가 있는것인가요? 또 그외의 await post.addHashatgs(result.map(r => r[0])); 이 코드는 9장 노드버드의 게시글 업로드 라우터의 일부분입니다 이 코드에선 add메서드를 사용했는데 result.map(r => r[0]) 를 Hashtag모델에 추가하는 것은 알겠지만 MySQL로 hashtags 테이블을 조회해보면 해당 데이터가 없습니다. 이 데이터는 return Hashtag.findOrCreate({ where: { title: tag.slice(1).toLowerCase() }, }) 여기서 생성되었습니다. 혹시 Post와 Hashtag가 다대다 관계이니 중간테이블에 저장했나 싶어 posthashtag를 조회해봐도 해당 데이터가 없습니다. 그렇다면 add, remove, set메서드를 사용했을 때 데이터는 어디에 저장되는 것인가요? 시퀄라이저 공식문서도 훝어봤지만 제가 원하는 정보가 안나와서 질문합니다.
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
post api 구현중에 sequelize에 계속 null값이 전송되어 질문드립니다
안녕하세요 제초로님 게시판에서 post api를 구성하던중에 database에 계속 null값이 전송되어 질문 드립니다 ● Post (service) ☞ bulkCreate를 사용하여 guideContent에 img ( 여러장 ), CourseInfor( 여러 코스들의 정보) 삽입합니다 ● controller ☞ req 항목들입니다 ● postMan req 1. id(PK) 값들은 전부 AutoIncrement입니다 2. req 값들은 전부 DataType 잘 지켜 삽입하였습니다 ●console.log(req.body ~~) ☞ console.log(req.body, req.imgs, req.courses) 의 값을 출력했을 때의 값입니다 (정상적으로 들어오고 있습니다) ●error ☞ Database에 INSERT하는 과정에서 Contents와 CourseInfor의 값이 Null 값으로 전송되고 있습니다 ☞ imgs 테이블의 값은 정상적으로 작동합니다 console에서도 값이 확실히 들어오고 table구성도 잘 했음에도 어디서 왜 null값이 들어오는걸까요..?
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
XSS방어 모듈 질문 드립니다.
helmet 하고 sanitize-html 둘다 XSS 방어 기능을 지원하더라구요.어느걸 쓰면 좋나요?helmet은 src나 href, 인라인 자바스크립트 XSS 공격을 막는 용도로sanitize는 <script> 태그 공격 막는 용도로 둘다 같이 쓰면 되나요?
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
api추가 질문입니다
api 추가 질문입니다. router.get('/search/:hashtag', async (req, res, next) => { try { const result = await request( req, `/posts/hashtag/${encodeURIComponent(req.params.hashtag)}`,// 문자를 UTF-8로 인코딩 ); res.json(result.data); } catch (error) { if (error.code) { console.error(error); next(error); } } }); 이 코드에서 :hashtag는 인코드 되어서 request함수에 넣었습니다. router.get('/posts/hashtag/:title', verifyToken, async (req, res) => { try { const hashtag = await Hashtag.findOne({ where: { title: req.params.title } }); if (!hashtag) { return res.status(404).json({ code: 404, message: '검색 결과가 없습니다', }); } const posts = await hashtag.getPosts(); return res.json({ code: 200, payload: posts, }); } catch (error) { console.error(error); return res.status(500).json({ code: 500, message: '서버 에러', }); } }); request함수는 헤더의 authorization에 토큰을 넣어서 이 라우터에 요청합니다. 그렇다면 이 코드의 :title 속성은 인코드된 문자열이지 않나요? Hashtag모델에 인코드된 문자열이 저장되는 것도 아니던데 왜 인코드된 문자열을 다시 디코드하지 않나요? const posts = await hashtag.getPosts(); return res.json({ code: 200, payload: posts, }); 또 Post에 있는 hashtag를 가져와 posts에 넣어서 json형식으로 출력했더니 이런 형태의 데이터가 나왔는데 Post모델에서 조건에 맞는 hashtag를 가져온것은 이해 했습니다. 그러나 PostHashtag테이블과 UserId컬럼은 왜 가져온것인가요? 혹시 관계 메서드 add set remove get에 대해 정확히 어떠한 인과관계가 나타는지 설명해주실수 있나요? 대충 느낌은 오지만 긴가민가 합니다 ㅜㅜ
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
nodebird-api코드 질문입니다
exports.verifyToken = (req, res, next) => { try { req.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET); return next(); } catch (error) { if (error.name === 'TokenExpiredError') { return res.status(419).json({ code: 419, message: '토큰이 만료되었습니다', }); } return res.status(401).json({ code: 401, message: '유효하지 않은 토큰입니다', }); } } 토큰을 검사하는 미들웨어 입니다 req.decode가 어떻게 생성되는지 궁금합니다. 또 jwt.verify함수가 토큰을 검사하는 함수로 알고있는데 토큰이 유효하다면 토큰을 req.decode에 넣는것인가요? 그리고 const result = await axios.get('http://localhost:8002/v1/test', { headers: { authorization: req.session.jwt }, }); axois.get 요청에 headers에 authorization부분에 세션을 넣던데 authorization 넣는 이유가 따로 있을까요? router.get('/posts/my', verifyToken, (req, res) => { Post.findAll({ where: { userId: req.decoded.id } }) .then((posts) => { console.log(posts); res.json({ code: 200, payload: posts, }); }) .catch((error) => { console.error(error); return res.status(500).json({ code: 500, message: '서버 에러', }); }); }); 이 부분에서 posts는 Post모델의 배열로 나오는데 그 앞에서 선언되지 않았음에도 불구하고 쓰던데 따로 규칙같은게 있나요? users면 User모델의 배열이라던가 등등...
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
이벤트루프강의에서 백그라운드 질문입니다
이벤트 루프 강의에서 백그라운드 질문입니다 콜 스택에서 setTimeout이 10번 호출해서 백그라운드에 setTimeout이 10개 등록되면 10개의 쓰레드가 setTimeout을 동시에 처리하나요 아니면 하나의 쓰레드가 setTimeout을 하나씩 순차적으로 10번 처리하나요? 만약 하나의 쓰레드가 순차적으로 10번 처리하면 멀티쓰레드라고 해봐야 콜스택의 쓰레드1 백그라운드의 쓰레드 1 그래서 겨우 2개의 쓰레드만 쓰는게 맞을까요? 너무너무 궁금합니다
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
.env를 html 파일에서 사용할 수 없을까요?
선생님 안녕하세요혹시 .env를 html에서 활용할 수 없나요? 환경변수를 html에서 사용하고 싶어서요
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
댓글 대댓글 구현중에 어려움이 있어 질문드립니다
● Comment Table 1. review Model의 PK를 받아 reviewId(FK)에 삽입하여 댓글을 작성합니다 2. comment Table 의 PK를 받아 commentID(FK)에 삽입하여 대댓글을 작성합니다 ( Self-Join 사용하였습니다) ● Get Comment ※ as : Recomment 는 commentId(FK)의 name입니다 ※ ● response 출력 오류 . 대댓글도 Comment Model의 PK를 갖고 있기 때문에 대댓글에 출력 된 이후에 일반 댓글에도 출력이 됩니다 이러한 경우에 댓글과 대댓글만 깔끔하게 뽑아내기 위해선 어떠한 해결 방법이 있을까요 ..?
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
nodebird-api서버(localhost:8002)에서 로그아웃이 안됩니다
req#logout requires a callback function Error: req#logout requires a callback function 혹시 코드가 잘못되었나 살펴봐도 아무런 이상이 없습니다. router.get('/logout', isLoggedIn, (req, res) => { req.logout(); // req.user 객체를 제거 req.session.destroy(); // req.session 객체의 내용을 제거 res.redirect('/'); // 초기화면으로 리다이렉트 }); 콜백함수가 필요하다는데 어떻게 해야하나요
- 미해결[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
캐싱 간단한 질문입니다
캐싱이 매번 deserlizeUser로 데이터 조회하지 않도록 객체를 만들어 거기에 유저의 데이터를 저장해서 사용하는 걸로 보입니다. 그렇다면 단순히 유저의 id만 저장해야 하나요 아니면 팔로잉테이블, 좋아요 테이블 등 전부 가져와야 하는 건가요? let cash = {}; passport.deserializeUser((id, done) => { if(!cash) { User.findOne({ where: { id }, include: [{ model: User, attributes: ['id', 'nick'], as: 'Followers', }, { model: User, attributes: ['id', 'nick'], as: 'Followings', }], }) .then(user => done(null, user)) .then(cash => cash = req.user) .catch(err => done(err)); } else { done(null, cash); } }); 이렇게 간단하게 코드를 짜봤습니다. cash객체를 선언하고 cash가 NULL이면 .then(user => done(null, user)) 이 코드에서 user 데이터를 req.user에 저장하기에 그 아래에 바로 cash = req.user로 데이터를 집어 넣습니다 그다음 cash가 NULL이 아니면 cash를 done합니다 그러나 Cannot read properties of undefined (reading 'length') 이러한 오류가 발생하는데 res.locals.followerCount = req.user ? req.user.Followers.length : 0; 오류가 난 코드는 이 코드 입니다. 실은 간단히 쳐본거라 접근방법이 틀린것 일수도 있지만 캐싱에 저장할 데이터가 너무 모호해서 질문 올립니다. 다른 스스로 해보기는 앞에서 한 작업에서 응용하는 거라 접근방법이 어느정도 다가오는데 캐싱하기는 제가 하는 접근이 맞는지 틀린지조차 애매합니다;;
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
혹시 <script> 태그 내에서 nunjucks를 사용할 수 있는지 질문드리고 싶습니다
선생님 안녕하세요항상 좋은 강의 가르쳐주시고, 질문을 받아주셔서 고맙습니다 공식문서를 찾아봤는데. 방법을 못찾아서 질문을 드리고 싶습니다Nunjucks (mozilla.github.io)혹시 아래의 사진처럼이렇게 랜더링으로 받은 변수 {{title}}을const b에 담고 싶은데, 혹시 방법을 가르쳐주시면 정말 감사하겠습니다 읽어주셔서 고맙습니다
- 해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
라우터 분리시킨 후, post 로 보낸 데이터를 못받아주는 문제가 생겨서 질문드리고 싶습니다
선생님 안녕하세요 라우터를 분리시키기 전에는 req.body가 post 로 보낸 데이터를 잘 받아줬습니다 그런데, 라우터를 분리시킨 다음에, post 로 보낸 데이터를 body가 못받아줘서 원인을 잘 모르겠어서 질문드리고 싶습니다 가르쳐주시면 정말 감사하겠습니다 먼저 폴더와 파일 위치입니다 url 에 localhost:3001 입력을 하면 먼저 app.js에서 이렇게 라우팅과 랜더링을 해줘서 signup.html 이 나옵니다 그리고 여기서 회원가입 버튼을 눌러봤습니다 누르면 이렇게 signup의 email nickname passwd가 manager.js 의 req.body.email, req.body.nickname에 전달될 줄 알았습니다 그러나 에러가 생겼습니다 라우터 분리 전에는 이런 일이 없었어서 혹시 원인을 가르쳐주시면 정말 감사하겠습니다 긴 질문을 읽어주셔서 고맙습니다 아래는 소스코드입니다 signup.html <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>회원가입 정보 입력란</title> </head> <style> .inputSubmit{ color:red; background-color: white; border-radius : 10% } </style> <body bgcolor="#FFFFFF"> <div align=center> <H2>회원가입 정보 입력란</H2> <HR> <form method="post" action="/add" name="form1"> <table width="650" border="0" align="center" cellspacing="0" cellpadding="5"> <tr><td>이메일</td><td><input type="text" name="email" size=30></td></tr> <tr><td>닉네임</td><td><input type="text" name="nickname" size=30></td></tr> <tr><td>비밀번호</td><td><input type="password" name="passwd" size=30></td></tr> <tr><td colspan="2" align="center"> <input type="submit" name="Submit3" value="회원가입" class="inputSubmit" id ='Submit3' onclick="document.querySelector('#Submit3').style.backgroundColor='grey'"></td></tr> </form> </table> </div> </body> </html> manager.js const express = require(`express`); const path = require('path'); const morgan = require('morgan'); const nunjucks = require('nunjucks'); const router = express.Router(); const { sequelize } = require('../models'); const {User} = require('../models'); const { userInfo } = require('os'); const { isNativeError } = require('util/types'); const app = express(); app.set('view engine', 'html'); nunjucks.configure('../views', { express: app, watch: true, }); sequelize.sync({ force: false }) .then( () => { console.log("DB connected"); }) .catch( (err) => { console.error(err); }) router.get('/',(req,res,next)=>{ res.render('signup',{}); }) router.post('/add',(req,res,next)=>{ console.log(req.body.nickname); console.log(req.body.email); try{ if(req.body.email) { User.create({ email: req.body.email, nickname: req.body.nickname, password: req.body.passwd, }); res.redirect('/'); } } catch(error) { console.log(error); next(error); } }) module.exports = router; app.js 입니다 /** * app.js */ const express = require('express'); const path = require('path'); const morgan = require('morgan'); const nunjucks = require('nunjucks'); const { sequelize } = require('./models'); const {User} = require('./models'); const { userInfo } = require('os'); const { isNativeError } = require('util/types'); const managerRouter = require('./routes/manager'); // const indexRouter = require('./routes'); // const usersRouter = require('./routes/users'); const app = express(); app.set('port', process.env.PORT || 3001); app.set('view engine', 'html'); nunjucks.configure('views', { express: app, watch: true, }); sequelize.sync({ force: false }) .then( () => { console.log("DB connected"); }) .catch( (err) => { console.error(err); }) app.use('/', managerRouter); app.use(morgan('dev')); app.use(express.static(path.join(__dirname, 'public'))); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use((req, res, next) => { const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`); error.status = 404; next(error); }); app.use((err, req, res, next) => { res.locals.message = err.message; res.locals.error = process.env.NODE_ENV !== 'production' ? err : {}; res.status(err.status || 500); res.render('error'); }); app.listen(app.get('port'), () => { console.log(app.get('port'), '번 포트에서 대기 중'); });