본 포스트는 내부망에서 별도 Proxy를 거치는 환경에서 Node.js 서버 구성 시 발생하는 SELF_SIGNED_CERT_IN_CHAIN 오류에 대한 원인 및 해결에 대한 글입니다.
Node.js 서버에서 Http를 생성하여 다른 서버와 통신하려 할 때 아래와 같은 오류가 발생하는 경우가 있습니다.
Error: self signed certificate in certificate chain
at TLSSocket.onConnectSecure (node:_tls_wrap:1530:34)
at TLSSocket.emit (node:events:390:28)
at TLSSocket._finishInit (node:_tls_wrap:944:8)
at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:725:12) {
code: 'SELF_SIGNED_CERT_IN_CHAIN'
}
위와 같은 경우는 대부분 내부망에서 외부망으로 통신할 때 별도의 Proxy 서버를 두고, 해당 Proxy 서버를 거칠 때 자체 사설 인증서로 통신할 경우에 발생합니다. 클라이언트가 서버와 통신하는 과정에서 신뢰할 수 있는 인증기관에서 발급된 인증서인지를 확인하는 과정을 거칠 때, 자체 서명된 사설 인증서가 인증 체인의 중간에 위치해서 발생하는 오류입니다.
테스트 용도로 사설 인증서를 사용하는 것이라면 추후 공인된 인증기관의 SSL로 변경하면 되겠지만 망분리로 인해서 발생하는 오류라면 테스트 환경일 경우에 아래 로직을 한 줄 추가해서 개발합니다.
ReferenceError: __dirname is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/Users/a20201022/Documents/expressServer/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
at file:///Users/a20201022/Documents/expressServer/src/app.js:7:34
at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:281:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
error Command failed with exit code 1.
오류 메시지 그대로 __dirname 이라는 전역 변수는 ES 모듈에서는 선언되지 않아 사용할 수 없다는 의미입니다. 해결을 위해서는 해당 변수를 아래와 같이 선언합니다.
본 포스트는 Node.js 에서 모듈 시스템 방식을 ES 방식을 사용했을 경우 발생하는 오류 및 해결에 대한 설명입니다.
Node.js의 모듈 시스템은 기본적으로 CommonJs 명세를 따릅니다. 하여 모듈을 사용할 경우에는 아래와 같이 require를 사용하여 필요한 모듈을 참조할 수 있습니다.
const express = require('express');
하지만 요즘은 많은 프로젝트 들에서 ES 기반의 모듈 시스템을 사용하여 아래와 같이 모듈을 참조할 수 있습니다.
import express from 'express';
위 두 구분은 동일한 역할을 하지만 Node.js 애플리케이션을 작성할 때 위와 같이 작성하면 서버를 구동할 때 아래와 같은 오류를 만나게 됩니다.
(node:1463) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/Users/a20201022/Documents/expressServer/src/app.js:1
import express from "express";
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1031:15)
at Module._compile (node:internal/modules/cjs/loader:1065:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
at node:internal/main/run_main_module:17:47
해당 오류를 해결하기 위해서는 package.json에 아래 한 줄을 추가합니다.
{
"type": "module"
}
위 설정은 프로젝트 전체에 적용되며 해당 프로젝트에 ES 기반의 모듈 시스템을 사용할 수 있게 해줍니다.
위와 같이 개발하면 UI에는 목록이 표시되지만 브라우저 콘솔 로그에 아래와 같은 오류가 나타납니다.
react.development.js:217 Warning: Each child in a list should have a unique "key" prop.
Check the render method of `ListView`. See https://reactjs.org/link/warning-keys for more information.
at NewsRow (webpack://searchNaverApi/./src/component/listview.component.jsx?:37:20)
at ListView (webpack://searchNaverApi/./src/component/listview.component.jsx?:91:66)
at div
at RecoilRoot_INTERNAL (webpack://searchNaverApi/./node_modules/recoil/es/index.js?:4225:3)
at RecoilRoot (webpack://searchNaverApi/./node_modules/recoil/es/index.js?:4391:5)
at App
React는 사용자가 개발한 컴포넌트의 상태가 변경되면 Re-Rendering을 하는데, 컴포넌트와 DOM의 Element 간의 관계를 생성할 때 "key" prop을 사용합니다. 따라서 key prop을 설정하지 않았다면 최초 1회는 문제 없이 Rendering을 했다 하더라도, 상태가 변경됨에 따라 오류들이 발생할 수 있습니다.
하지만 위 코드는 샘플에서나 사용할 뿐, 실제로는 되도록 해당 배열에서 고유한 값을 사용해야 합니다. JavaScript의 배열은 동적으로 변경이 일어날 수 있으므로 인덱스 값은 언제든지 변할 수 있습니다. 위와 같은 경우의 예라면 뉴스의 게시물 번호 등을 사용해서 해당 Row에서 변하지 않는 고유한 값을 사용하는게 가장 좋습니다.