문제상황
ImageUs프로젝트의 서비스는 개인의 이미지 클라우드를 제공하는 것이기 때문에 이미지를 저장하는 및 다운하는 서버가 따로 필요한데 AWS의 s3나 네이버의 사진클라우드를 이용 할 수 있지만 자칫 관리를 잘못하면 비용이 들 수 있다.
일반적인 백엔드 서버와 이미지 서버를 합쳐서 구동 할 경우 한 서버가 에러가 났을 때 둘 다 기능을 상실 할 수 있다.
해결방법
적용과정
*images라는 폴더에 개인 유저의 id이름의 폴더를 만들고 그 안에 유저의 사진들을 저장
route
POST /room/room_id/image (방에 이미지 업로드)
header:'Authorization'
file:'image'
res: json
{
"image_info": {
"id": 3,
"link": "30/example3.jpg",
"user_id": 2,
"created_at": "2023-01-01 10:10:10 UTC+09:00"
},
"success": 3
}
POST /image (이미지 업로드)
header:'Authorization'
file:'image'
res: json
{
"image_info": {
"id": 3,
"link": "30/example3.jpg",
"user_id": 2,
"created_at": "2023-01-01 10:10:10 UTC+09:00"
},
"success": 3
}
POST /upload/user_id (유저의 이미지 업로드)
header:'Authorization'
file:'image'
res: text(image의 다운로드 링크)
30/example3.jpg
GET /image-download/user_id/filename (특정 사진 다운로드)
header:'Authorization'
res: image_file
전체 구조
BackServer에 유저가 로그인 했을 때 받은 access_token과 함께 이미지를 업로드 하는데 BackServer에 저장된 이미지 업로드를 위한 secret_key로 토큰을 만들어 ImageServer에 같이 보내고 있다
이미지를 업로드 하려면 BackServer를 반드시 거쳐야 하고 유저가 ImageServer에 직접 업로드 하는 것을 막는다.
def save_profile_picture(self,user_id,image):
#이미지의 이름 추출
image_filename=image.filename
#이미지를 바이트형식으로 읽기
image=Image.open(BytesIO(image.read()))
#이미지 저장 경로 설정
image_save_dir=f"{parent_path}/{self.config['IMAGE_PATH']}/{user_id}"
#이미지 저장 경로 존재 확인
is_user_dir_exists=os.path.isdir(f"{image_save_dir}")
#존재하지 않는 다면 유저를 위한 폴더 생성
if not is_user_dir_exists:
os.makedirs(image_save_dir)
#이미지 저장 이름 설정
image_path_and_name=f"{image_save_dir}/{image_filename}"
#이미지의 파일형식과 이름 분리
image_dir_and_name,image_ext=os.path.splitext(image_path_and_name)
#중복숫자 초기설정
uniq=1
#이미지의 저장 경로 초기값 설정
output_path=image_path_and_name
#이미지의 저장 경로가 존재하지 않을 때까지 숫자를 경로에 1씩 추가
while os.path.exists(output_path):
output_path=f"{image_dir_and_name}({uniq}){image_ext}"
uniq+=1
print(output_path)
#이미지 저장
image.save(output_path)
image.close()
image_link=f"{user_id}/{output_path.split('/')[-1]}"
return image_link
*사용자가 같은 이름으로 된 사진을 올릴 수 있기 때문에 같은 이름의 사진이라면 고유한 사진의 이름이 될때까지 이름 뒤에 숫자를 추가해 주는 형식
(sample.jpg가 존재한다면 sample(1).jpg,sample(1).jpg가 존재한다면 sample(2).jpg식으로 최종 저장 경로 결정)