일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- Git
- aws
- 코드잇
- SQL
- redis
- 코딩테스트준비
- Python
- 개발자취업
- 파이썬프로그래밍기초
- node.js
- 방송대
- 방송대컴퓨터과학과
- 코딩테스트
- 항해99
- Cookie
- 유노코딩
- TiL
- MySQL
- nestjs
- HTML
- 중간이들
- 꿀단집
- CSS
- 파이썬
- JavaScript
- 엘리스sw트랙
- presignedurl
- 프로그래머스
- 99클럽
- 데이터베이스시스템
- Today
- Total
배꼽파지 않도록 잘 개발해요
[꿀단집] 배포환경에서 multer로 프로필 이미지 변경이 안 되는 문제 - 서버 파일 경로 구분자 문제를 path.normalize로 해결 본문
[꿀단집] 배포환경에서 multer로 프로필 이미지 변경이 안 되는 문제 - 서버 파일 경로 구분자 문제를 path.normalize로 해결
꼽파 2024. 9. 10. 16:37우리 서버에서 multer를 활용하여 프로필 이미지를 변경할 수 있는 기능이 있다.
클라이언트에서 사진을 업로드하면 서버에서 multer를 통해 이미지를 서버의 public/uploads 폴더 안에 저장을 하고, 해당 이미지 경로를 DB의 사용자 정보에 저장한다.
이걸 클라이언트가 받아서 화면에 렌더링하는 식으로 구현을 하였다.
문제는 로컬에서는 아주 잘 작동을 하였으나, 배포 후 작동을 하지 않는다는 것이었다.
여기 모달창에서 왼쪽 프로필이미지 버튼을 누르면 변경할 수 있는 창이 뜬다.
여기서 미리보기로 바뀐 이미지가 뜨고, 저 모달창을 닫아도 변경된 이미지가 렌더링되어야 한다.
이걸 내가 구현하였는데, 순서가 헷갈려서 시간이 꽤 걸렸던 기억이 났다.
프론트엔드는 렌더링 되는 화면과 데이터 로직을 모두 고려해야해서 어려운 것 같다.
이런 문제가 발생할 경우 프론트엔드/백엔드/로컬환경/배포환경을 모두 살펴봐야한다.
분명히 배포 서버에서 문제가 생긴 것 같았는데, 일단 프론트엔드 상황도 한번 더 점검을 하기로 하였다.
이 유저 정보 불러오는 부분에서 서버에서 profileImage를 잘 불러오는지 console.log를 통해 확인하였다.
콘솔로 출력해보니 이미지가 불러와지지 않았다.
배포 서버와 통신을 할 때 배포 서버의 CNAME으로 요청을 보내고 있다.
프론트엔드 측에서 이미지가 존재하지 않을 경우 기본 프로필 이미지를 넣어주는 것으로 설정하였다.
서버에서 이미지 URL을 처리할 때 문제가 생긴 것 같았다.
지금 Request URL을 보니까 'src/public/uploads/profileImage-어쩌구'가 404 Not Found 에러가 떴다.
여기서 이상함을 느꼈다. Express 서버에서 asset 파일은 public 경로 안으로 저장되도록 설정하였기 때문이다.
MongoDB에서 배포 서버에서 저장된 프로필이미지 경로를 확인해보았다.
'src/public/uploads/profileImage-어쩌구' 로 저장이 된다. 이게 문제였다.
실제 배포 서버에는 이미지가 잘 저장이 된다. 이로써 경로를 저장할 때가 문제가 있다는 것이 확정되었다.
src/public/uploads 이런식으로 URL이 지정되어 있으면 서버에서는 이를 인식하지 못한다.
express의 app.js에 설정된 내용
// 정적파일 경로 설정
expressApp.use(express.static(path.join(__dirname, 'public')));
public 폴더 안에 정적파일을 넣을 것이라고 설정을 해 놓은 상태이다.
올바른 경로
{배포서버의CName}/uploads/profileImage-1234
→ public 안에 있는 것부터 써야 서버가 인식을 한다.
틀린 경로
{배포서버의CName}/src/public/uploads/profileImage-1234
→ 이러면 서버가 인식을 못한다.
코드를 살펴보니 아래 부분이 문제였다.
user.profileImage = imageUrl.replace('src\\public\\', '');
내 컴퓨터는 윈도우에서 실행되지만, 배포 컴퓨터는 리눅스에서 실행되기 때문에 이 경로 구분자가 인식이 되지 않았던 것이다.
그리하여 저 코드가 실행되지 않고, 경로가 src부터 그대로 저장이 되어 서버가 이미지를 찾을 수 없었던 것이었다.
윈도우에서는 \ (역슬래시)를 사용하지만, 리눅스에서는 / (슬래시)를 경로 구분자로 사용한다.
프로필 이미지 변경 서비스 코드를 아래와 같이 변경하였다.
// 프로필 이미지 변경
async uploadProfileImage(req) {
return new Promise((resolve, reject) => {
multerConfig.getUploadHandler()(req, null, async (err) => {
if (err) {
if (err.code === 'LIMIT_FILE_SIZE') {
reject({
success: false,
message: 'File size limit exceeded.',
});
} else {
console.error('Error uploading profile image:', err);
reject({
success: false,
message: 'Failed to upload profile image.',
});
}
} else {
try {
const imageUrl = req.file.path;
// JWT 토큰에서 사용자 이메일을 추출하여 사용자 정보 가져오기
const token = req.headers.authorization.split(' ')[1];
const decodedToken = jwt.verify(token, config.jwtSecret);
const userId = decodedToken.id;
// 사용자 찾기
let user = await userDAO.findById(userId);
if (!user) {
throw new AppError(
commonErrors.resourceNotFoundError,
'해당 이메일로 가입한 회원이 없습니다.',
400,
);
}
// 사용자 정보 업데이트
// 윈도우는 경로 구분자가 '\', 리눅스는 '/'를 사용하여 배포환경에서 이 코드가 동작하지 않았음.
// user.profileImage = imageUrl.replace('src\\public\\', '');
const normalizedPath = path.normalize(imageUrl);
user.profileImage = normalizedPath.replace(path.join('src', 'public') + path.sep, '');
const newProfileImage = user.profileImage;
user = await userDAO.updateById(userId, {
profileImage: newProfileImage,
});
resolve({ success: true, imageUrl: newProfileImage });
} catch (error) {
console.error('Error saving profile image URL:', error);
reject({
success: false,
message: 'Failed to save profile image URL.',
});
}
}
});
});
}
}
user.profileImage = normalizedPath.replace(path.join('src', 'public') + path.sep, '');
- path.join('src', 'public') : src/public 또는 src\public
- path.sep : / 또는 \
- path.join('src', 'public') + path.sep : src/public/ 또는 src\public\
이걸 replace를 활용하여 빈 문자열로 변환하여 제거한다.
마지막으로 normalizedPath를 활용하여 윈도우와 리눅스 환경에서 모두 일관되게 동작하도록 하였다.
Node.js Path.normalize 관련 내용
https://nodejs.org/api/path.html
Path | Node.js v22.8.0 Documentation
Path# Source Code: lib/path.js The node:path module provides utilities for working with file and directory paths. It can be accessed using: const path = require('node:path'); copy Windows vs. POSIX# The default operation of the node:path module varies base
nodejs.org
path.normalize를 사용하면 POSIX (유닉스 계열 운영체제)와 Windows에서 각각 해당 운영체제에 맞는 경로 구분자로 표기가 된다는 내용이다.
이를 수정하고 배포환경에서 잘 동작하는 것을 확인하였다.
글 내용 요약
원인
- 서버에서 파일을 저장하고 해당 경로를 유저 프로필 이미지 URL로 DB에 저장할 때, 윈도우와 리눅스의 경로 구분자 차이로 인해 문제가 발생하였음.
- 윈도우는 \를, 리눅스는 /를 사용하기 때문에, 경로 처리 코드가 환경에 따라 다르게 동작했음.
해결
- Node.js의 path.normalize를 사용하여 경로를 표준화한 후, path.join과 path.sep을 이용해 경로를 올바르게 처리하도록 수정함.
- 이로 인해 로컬 환경과 배포 환경 모두에서 일관된 경로 처리가 가능하게 되었음.
'Project' 카테고리의 다른 글
[중간이들] SMS 인증번호 발송서비스 플랫폼으로 네이버 클라우드를 선택하지 않은 이유 (0) | 2024.09.10 |
---|---|
[꿀단집] 구글 OAuth 소셜 로그인: 심사 통과 후 프로덕션 환경에서 외부인 로그인 가능 (2) | 2024.09.10 |
[중간이들] Google Cloud API로 NestJS에 OCR 기능 추가 - 타입 오류 해결 및 원하는 문자열 추출 (0) | 2024.09.10 |
[꿀단집] 구글 검색 콘솔에 사이트 등록 및 사이트맵 만들기 (0) | 2024.09.02 |
[MoneyManyBank] - TKinter로 GUI 프로그램 ① 화면 설계 (0) | 2023.12.09 |