node.js express 관련 질문입니다.

카테고리에 node.js가 없어서 일단 JavaScript로 정했습니다.
만약에 아래와 같은 코드가 있다고 가정할 때

// app.use("/product/product1", product1Router);
// app.use("/product/product2", product2Router);
// app.use("/product/product3", product3Router);

여기서 숫자 1, 2, 3 이 부분을 반복문을 이용해서 하나의 app.use()로 3개의 미들웨어를 만든다고 가정하고 아래와 같은 코드를 짰습니다.

let i;
let j;
for (i = 1; i <= data; i++) {
    for (j = 1; j <= funcBox.length; j++) {
        if (i === j) app.use(`product/product${i}`, funcBox[j]);
    }
}

두 반복문의 인덱스 숫자가 같을 때 app.use()가 실행되기를 바라며 코드를 짰습니다. 그런데 실제 실행을 하게 되면 ReferenceError: __dirname is not defined 에러가 나더라고요. 위 반복문을 쓰지 않고

// app.use("/product/product1", product1Router);
// app.use("/product/product2", product2Router);
// app.use("/product/product3", product3Router);

이런 식으로 사용할 때는 에러가 전혀 없고 실행이 잘됩니다.
제가 궁금한 것은 app.use() 의 매개 변수를 반복문의 인덱스를 대입하면 안되는 것일까요?

funcBox[0]product1Router가 들어있는 건 아닌가요?

매번 답변 달아주셔서 감사합니다! 그런데 배열의 인덱스가 0부터 시작한다는 것을 알아서 funcBox[0]에 product1Router가 아닌 다른 값을 넣어두었고 data 변수에는 프로미스 함수로부터 받은 인스턴스 값(3)이 들어있습니다. 이렇게 되면 i <= data과 j <= funcBox.length 의 범위가 각각 3으로 맞아 떨어지게 됩니다.
제가 혹시나 해서 반복문을 사용하지 않고 아래처럼 코드를 작성했더니

app.use(`/product/product${1}`, funcBox[1]);
app.use(`/product/product${2}`, funcBox[2]);
app.use(`/product/product${2}`, funcBox[3]);

정상 작동 되더라고요. 그래서 제가 app.use() 의 매개 변수를 반복문의 인덱스를 대입하면 안되는 것인가에 대해 질문한겁니다.
혹시 전체코드가 궁금하시다면 github주소를 보내드릴까요??

일단 product/product${i}인 것이 마음에 걸리지만, 기존의 /product/product${i}인 것인데 오탈자가 난 것으로 하고 넘어가도록 하겠습니다. 예상되는 이유로는 아래와 같습니다.

  1. funcBox 안에 있는 아이템에서 __dirname을 해석하는 데에서 문제가 생겼다.
    __dirname은 실제 자바스크립트 파일이 실행되는 디렉토리의 변수인데, 이것이 정의되지 않는 경우가 종종 있는 듯합니다.

해결 방법은 링크에 있습니다.

  1. 문제가 없다면 정말로 반복문의 문제일 가능성이 있다.

사실 원리상 반복문을 썼다고 해서 오류가 날 일은 없는데, 원래 코드를 모르니 반복문이 원인이 아닐 것이라고 확신 또한 할 수 없습니다.
일단 원인을 추리기 위해 express에서 __dirname이 정의되지 않는 오류를 찾아봤지만, 딱히 눈에 띄는 사례는 찾지 못하였고요. 하지만 배열의 원소를 일일이 할당하니 정상 작동은 하더라는 내용을 통해 data 변수가 원인이 아닐까 추측됩니다.

2-1. data가 원인으로 지목되는 이유에는 app#use의 원리에 있다.

원리를 아시고 쓰는 것인지 확신할 수 없지만, app#use의 경우, 실행한다고 하는 일반적인 함수보다는, 이벤트가 발생했을 때 실행할 콜백함수를 등록하는 메소드라고 보시는 게 이해하기 쉬울 겁니다. 그렇기에 예를 들어

app.use("/product/product1", funcBox[1]);

이렇게 선언돼 있다면 저 코드가 선언된 시점 이후부터 저 라우터가 작동할 겁니다. 그렇기에 그럴 일이 없다고 거의 확신하지만 만에 하나 라우터 호출 시점이 라우터 정의 시점보다 이르기 때문에 생긴 게 아닐까 추측합니다. 그렇기에 프로미스로 값이 정의되는 data에 의존하지 않을 수 있다면 의존하지 않고 라우터를 정의하는 게 좋겠죠.

for (let i = 1; i <= funcBox.length; i++) {
  app.use(`product/product${i}`, funcBox[i]);
}

더 간략하게 하면 이렇게도 할 수 있습니다.

funcBox.foreach((fn, i) => { 
  if (i > 0) app.use(`/product/product${i + 1}`, fn); 
});

답변 감사합니다. 그런데 특이하게

for (let i = 1; i <= funcBox.length; i++) {
  app.use(`product/product${i}`, funcBox[i]);
}

이 코드가 에러가 납니다. 에러 내용이 TypeError: Router.use() requires a middleware function but got a undefined 이렇더라고요. 아마 funcBox[i] 이것 때문인 거 같은데 왜 반복문을 돌릴때만 undefined인지 모르겠습니다. 평범하게 funcBox[1] 이런식으로 콘솔로 찍어보면 문제가 없습니다. 그리고

funcBox.foreach((fn, i) => { 
  if (i > 0) app.use(`/product/product${i + 1}`, fn); 
});

이 코드에서는 에러는 없습니다. 그런데 제가 /product/product1로 get 요청을 보내면 ReferenceError: __dirname is not defined이 오류가 또 나옵니다. 신기하게 product2는 잘 나오게 되는데 product3은 product2의 내용이 나옵니다. 코드 전체 흐름을 모르면 문제를 파악하기 힘드실 수 있으니 github 주소를 공개해드릴게요

p.s 혹시 제가 package.json에 “type”:"module"을 추가해서 ecma형식으로 사용하는데 그것이 문제가 될까요?

깃허브 코드를 보니 정말로 오탈자 난 것이 오류의 원인이었네요. /를 추가하시면 문제가 해결될 것 같습니다. 그리고 __dirname이 undefined인 에러는 __dirname을 define 해주시면 해결될 것 같습니다.

app.use((req, res, next) => {
    res.status(404).sendFile(path.join(__dirname, "/404error.html"));
    throw new Error("404");
});

덕분에 해결 되었습니다! 결국 문법적인 오류가 아닌 저의 실수였네요 캐치하지 못한 부분 잡아주셔서 감사합니다!

1개의 좋아요