(node:498071) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_CALLBACK]: Callback must be a function at makeCallback (fs.js:136:11) at Object.rmdir (fs.js:671:14) at router.get (/ServerCrwal.js:499:16) at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5) at next (/node_modules/express/lib/router/route.js:137:13) at Route.dispatch (/node_modules/express/lib/router/route.js:112:3) at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5) at /node_modules/express/lib/router/index.js:281:22 at Function.process_params (/node_modules/express/lib/router/index.js:335:12) at next (/node_modules/express/lib/router/index.js:275:10) (node:498071) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:498071) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
2. 원인
버전에 맞지 않는 구문을 사용해서 그렇다.
rmdir을 recursive 옵션 없이 사용하면 잘 작동하는데 문제가 발생한 환경의 node 버전은 10.x 버전이었다. 그리고 인터넷에 올라와있는 예시는 거의 12버전 이상에서 작동하는 코드들이다.
왼쪽이 10.x 구문, 오른쪽이 12.x 구문이다.
문제가 발생했다면 해당 환경해서 node -v로 버전을 확인해보고 12버전이상인지 확인해보자.
filesystem파일에 대하여 관리할 수 있도록 도와주는 라이브러리 이미 fs로 쓰고 있을 가능성이 높음.
마찬가지로 코드로 넘어가기 전에 간단히 어떤 플로우를 통하여 업로드 하는지 알아보자.
업로드보다 조금 더 쉽다.
1. axios에서 원하는 파일 데이터를 stream 형태로 요청
2. 결과값을 writestream으로 저장
3. 코드
//1. axios에서 원하는 파일 데이터를 stream 형태로 요청
AxiosNetworkHelper.GetRequest({
url: 'https://targetsite.com/image.jpg',
responseType: 'stream',
}).then((res) => {
//폴더 recursive로 생성 요청
if (!fileSystem.existsSync(`./images/savefolder`))
fileSystem.mkdirSync(`./images/savefolder`,{recursive: true})
//파일 이름 확장자명 따라서 정해주기
let fileName = `filename.${res.headers['content-type'].split('/')[1]}`
//2. 결과값을 writestream으로 저장
const writer = fileSystem.createWriteStream(`./images/savefolder/${fileName }`);
res.pipe(writer)
writer.on('error', (error) => {console.log(`이미지 다운로드 스트림 생성 실패 ${error}`)})
writer.on('close', () => {console.log('이미지 다운로드 성공')})
}).catch(error => {LogManager.getInstance().AddLocalLogData(forkHistoryId, `이미지 다운로드 요청 실패 ${error}`)})
마찬가지로 내용이 쉽기 때문에 자세한 설명은 생략하도록 하겠다.
다만 파일 확장자를 따로 정해주는 부분은 이해가 안갈수도 있는데
해당 res.headers 부분을 찍어보면 아래와 같이 나온다.
확장자 정보는 url을 통해서 이미 알고 있는데 왜 다시 정보를 이런식을 받아오냐 묻는다면... 가끔 확장자 정보가 없는 경우가 있다. 그런 경우 위와 같이 확장자를 그때그때 받아와서 저장하는 것 이다.