inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

Node.js 교과서 - 기본부터 프로젝트 실습까지

multer로 이미지 업로드하기

Main.pug 파일에 과 정적파일에 관한 질문입니다.

335

ryu sin

작성한 질문수 28

0

※파일 전체의 코드는 질문 하단에 있습니다.

안녕하세요. 항상 최고의 node.js 강좌 잘 듣고 있습니다.

질문은 두개 입니다.

  1. main.pug 파일을 보면 다음과 같은 부분이 있습니다.

    [].forEach.call(document.querySelectorAll('.twit-follow'), function (tag) {

    tag.addEventListener('click', function () {

[] 부분이 이해가 안갑니다. 빈 리스트를 forEach 하는게 어떻게 가능한지요. "변수".forEach라면 모르겠는데...

이 부분에는 어떤 값이 어떻게, 언제 오기에 저 문법이 가능한지 알고 싶습니다.

  1. 정적파일은 기왕이면 다른 미들웨어들 위에 두라고 하신 부분이 이해가 잘 되지 않습니다.

    예를 들어,

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));

위와 같은 코드에서 morgan 뒤쪽에 static middleware 를 위치 시켜서, 다른 미들웨어들이 불필요하게 사용되지 않게 해서 자원을 아끼라고 말씀하셨습니다.

그러나, 미들웨어들은 일단 실행되면 (next() 가 있다는 가정하에, 에러가 없다면) 순서대로 마지막 미들웨어까지 계속 나가야 하는것 아닌가요? 결국 위에 위치시키나, 아래 위치시키나 다른 미들웨어들을 실행하는건 마찬가지 같은데요.

a) express.static은 next()가 없는 건가요?

b)만약 express static이, 다음 미들웨어를 실행하지 않고 저기서 끝난다면, app.js 파일을 사용할 때마다 모든 요청이 전부 express.static 에서 끝나 버릴텐데, 그럼 json, eurlencoded, cookieParser 등등도 사용할 수 없게 되는 거 아닐까요?

혹시 express.static은 특정 요청에만 응답하고, 일반적인 요청에는 응답을 안하는 기능이 있는 건가요? 그렇다고 하면, 결국 이 명령어를 상위에 위치시킬 필요는 없는것 같은데요.

main.pug 파일 -----------

extends layout

block content

.timeline

if user

div

form#twit-form(action='/post' method='post' enctype='multipart/form-data')

.input-group

textarea#twit(name='content' maxlength=140)

.img-preview

img#img-preview(src='' style='display: none;' width='250' alt='미리보기')

input#img-url(type='hidden' name='url')

div

label#img-label(for='img') 사진 업로드

input#img(type='file' accept='image/*')

button#twit-btn.btn(type='submit') 짹짹

.twits

form#hashtag-form(action='/post/hashtag')

input(type='text' name='hashtag' placeholder='태그 검색')

button.btn 검색

for twit in twits

.twit

input.twit-user-id(type='hidden' value=twit.user.id)

input.twit-id(type='hidden' value=twit.id)

.twit-author= twit.user.nick

-const follow = user && user.Followings.map(f => f.id).includes(twit.user.id);

if user && user.id !== twit.user.id && !follow

button.twit-follow 팔로우하기

.twit-content= twit.content

if twit.img

.twit-img

img(src=twit.img alt='섬네일')

script.

if (document.getElementById('img')) {

document.getElementById('img').addEventListener('change', function (e) {

var formData = new FormData();

console.log(this, this.files);

formData.append('img', this.files[0]);

var xhr = new XMLHttpRequest();

xhr.onload = function () {

if (xhr.status === 200) {

var url = JSON.parse(xhr.responseText).url;

document.getElementById('img-url').value = url;

document.getElementById('img-preview').src = url;

document.getElementById('img-preview').style.display = 'inline';

} else {

console.error(xhr.responseText);

}

};

xhr.open('POST', '/post/img');

xhr.send(formData);

});

}

[].forEach.call(document.querySelectorAll('.twit-follow'), function (tag) {

tag.addEventListener('click', function () {

var isLoggedIn = document.querySelector('#my-id');

if (isLoggedIn) {

var userId = tag.parentNode.querySelector('.twit-user-id').value;

var myId = isLoggedIn.value;

if (userId !== myId) {

if (confirm('팔로잉하시겠습니까?')) {

var xhr = new XMLHttpRequest();

xhr.onload = function () {

if (xhr.status === 200) {

location.reload();

} else {

console.error(xhr.responseText);

}

};

xhr.open('POST', '/user/' + userId + '/follow');

xhr.send();

}

}

}

});

});

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 flash = require('connect-flash');

const passport = require('passport');

require('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 passportConfig = require('./passport');

const app = express();

sequelize.sync();

passportConfig(passport);

app.set('views', path.join(__dirname, 'views'));

app.set('view engine', 'pug');

app.set('port', process.env.PORT || 8001);

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(flash());

app.use(passport.initialize());

app.use(passport.session());

app.use('/', pageRouter);

app.use('/auth', authRouter);

app.use('/post', postRouter);

app.use('/user', userRouter);

app.use((req, res, next) => {

const err = new Error('Not Found');

err.status = 404;

next(err);

});

app.use((err, req, res) => {

res.locals.message = err.message;

res.locals.error = req.app.get('env') === 'development' ? err : {};

res.status(err.status || 500);

res.render('error');

});

app.listen(app.get('port'), () => {

console.log(app.get('port'), '번 포트에서 대기중');

});

nodejs mysql javascript mongodb

답변 2

0

ryu sin

답변 감사합니다. 정말 최고입니다 ! : )

0

제로초(조현영)

[].forEach.call 문법은요. 빈 배열을 forEach를 도는게 아니라 배열에서 forEach 메서드를 빌려(call 메서드가 그 역할을 해줍니다) 유사배열(forEach 메서드가 없음)에 적용하는 것입니다.

아 그런데 생각해보니 document.querySelectorAll()은 유사배열이지만 forEach를 제공하네요. 제 실수입니다.

express.static에 관해서는요. 이것은 정적 파일을 찾으면 res.sendFile을 하고, 못 찾으면 next()를 합니다.

미들웨어는 위에서부터 순차적으로 실행되기 때문에(next()로 다음으로 넘겨주고요)

파일을 찾아서 res.sendFile을 한 경우에는 다음 미들웨어가 실행되지 않습니다. 그렇기 때문에 최대한 위로 올려야 쓸데없는 미들웨어들이 실행이 되지 않고요. 못 찾은 경우에는 next()를 내부적으로 해서 다음 미들웨어로 넘어갑니다.

실제 서비스에서도 cluster를 사용하나요?

1

314

2

캐싱에 관하여

0

279

3

salt를 실무에서 사용할때 항상 randomBytes로 만들어줘야 하나요?

0

347

1

게시물 올리기 오류

0

408

1

캐슁 이후 로그인창

0

266

1

kakao passport 질문있습니다.

0

493

3

global객체 공유 질문드립니다.

1

418

1

서버가 죽어버리네요

0

1047

8

포링키 문제..

0

235

2

커넥션 플래시 설치문제

0

216

2

익스프레스 제너레이터? 설치문제

0

2586

6

redis 질문입니다.

0

305

1

9장 세션을 DB에 저장시 리다이렉션 오류 발생

0

874

8

프레임워크 선택에 관하여 질문이 있습니다.

0

300

3

시퀄라이즈 질문입니다 ! !

0

588

1

리뉴얼 강의 12강 socket.io에서 req.session접근 관련 질문

0

922

6

oAuth 질문입니다.

0

356

3

GCP 질문입니다.

0

366

1

Passport 모듈 로그인 구현관련

0

720

6

카카오 로그인 관련 질문입니다!!

0

606

4

스스로 해보기 10-16 nunjuncks 질문있습니다

0

499

5

제로초님 HTTP 완벽가이드 추천해주신거 너무 잘 읽었습니다.

0

317

2

gif채팅방 nunjucks관련 질문입니다!

0

338

3

현영님 몽고db관련 질문입니다.

0

233

3