1. 요약
- 목적
- 이미지 전송 원리 이해
- 동기
- 현재 제작하고 있는 프로젝트의 더 깊은 이해
- 현 프로젝트에서는 이미지를 GCS에 저장하여 사용하고 있음
- 해당 이미지 전송에 대한 이해도가 부족하다고 생각되어, 이미지 전송 과정을 공부하고자 함
- 현재 제작하고 있는 프로젝트의 더 깊은 이해
- 과정
- FE → BE로 이미지 전송하는 과정을 그리기
2. FE
- 요약
- 통신 방법
- XML
- XHL
- XMLHttpRequest
- AJAX
- 데이터 형식
- MIME-TYPE
- Content-Type
- multipart/*
- multipart/form-data
- 통신 방법
- XML
- 데이터 표기 방법 중 하나
- 데이터 전송 시, xml 형식으로 데이터 정보 기술 가능
- 예시
- 데이터 표기 방법 중 하나
<book>
<title>Harry Potter</title>
<author>J.K. Rowling</author>
<year>1997</year>
</book>
- XHL
- 비동기 통신 방법
- XML, JSON 등의 데이터를 주고받게 됨
- 이점
- 페이지 새로고침 없이 최신 정보로 업데이트
※ 동기 / 비동기 통신
- 동기
- 상대방의 응답이 올때가지 일을 하지 않음
- 예시
- 상대방에게 요청 보냄 → 상대방에게 응답 받음 → 다음 일 수행
- 비동기
- 상대방의 응답을 기다리지 않고 다음 작업 수행
- 목적
- 일부 페이지만 리렌더링 시키는 것
- 전체 페이지 새로고침 없이 일부만 비동기적으로 처리해서 페이지를 사용하는 걸 목적으로 함
- 예시
- 상대방에게 요청 보냄 → 다음 일 수행 → 상대방에게 응답 받음
- XMLHttpRequest
- XHL 형식의 통신을 가능하게 해주는 객체
- 해당 객체로 통신 시, 상대방의 응답을 기다리지 않고 내 작업을 계속 수행
- 예시
- XHR : GET 요청 보내기
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true); // true -> 비동기 요청
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
// 서버 응답을 처리
console.log(xhr.responseText);
}
};
xhr.send();
//send() 이후, 응답을 기다리지 않고 다음 작업 수행
- AJAX
- XHL을 이용해서 비동기 통신을 수행함
- XMLHttpRequest로 XHL을 사용함
- 이점
- 웹페이지 동적 업데이트
- XHL만 이용해서는 새로고침 없이 웹페이지를 동적으로 업데이트하기에는 난이도가 있음
- AJAX는 XHL을 편리하게 사용할 수 있도록 구성함으로써, 동적 업데이트를 쉽게 구현 가능
- 웹페이지 동적 업데이트
- XHL을 이용해서 비동기 통신을 수행함
- MIME-TYPE
- 요약
- 인터넷 통신에서 데이터 타입을 정하는 표준
- (인터넷 통신 : HTTP 통신, 이메일 통신, …)
- 인터넷 통신에서 데이터 타입을 정하는 표준
- 예시
- 웹 페이지: text/html
- 이미지 파일: image/png, image/jpeg
- JSON 데이터: application/json
- PDF 파일: application/pdf
- 요약
- Content-Type
- 요약
- HTTP 통신에서 Request Body 데이터에 대한 MIME-type 지정
- 설명
- POST 요청 시, Request Body에 요청 데이터를 첨부한다.
- 요청을 받는 입장에서는 Content-Type을 통해 요청 데이터의 형식을 이해할 수 있다.
- 예시
- XHL
- HTTP Method : POST
- Content-Type : JSON
- XHL
- 요약
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://example.com/upload', true);
// 요청 헤더에 MIME-TYPE 설정
xhr.setRequestHeader('Content-Type', 'application/json'); // JSON 데이터 전송
// 요청 보내기
var data = JSON.stringify({ name: 'John', age: 30 });
xhr.send(data);
- multipart/*
- 요약
- 여러 타입의 데이터를 한 번에 보내기 위한 Content-Type
- 설명
- image, text 등의 한정된 Content-Type으로는 Form Request를 보내기 어렵다.
- 예를 들어, 사진 및 설명 글을 백엔드에 요청 시, 여러 번 나누어서 Request를 보내야 한다.
- 그때, multipart는 여러 타입의 데이터를 한 번에 보낼 수 있다.
- multipart는 boundary라는 문자열로 각 타입의 데이터를 분리함
- 종류
- multipart/form-data
- 텍스트 및 파일 동시 전송
- 각 타입의 데이터들은 name 필드로 구분됨
- HTML Form 데이터 전송할 때 좋음
- 예시
- 받는 입장에서는 name을 통해 각 데이터를 가져오는게 가능함
- multipart/form-data
- 요약
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----Boundary123
------Boundary
Content-Disposition: form-data; name="username"
john_doe
------Boundary
Content-Disposition: form-data; name="file"; filename="example.jpg"
Content-Type: image/jpeg
(binary data)
------Boundary--
- multipart/alternative
- 동일한 내용을 서로 다른 타입으로 보냄
- 응답을 받는 입장에서는 자기가 원하는 타입으로 골라 받음
- multipart/mixed
- 텍스트 및 파일 동시 전송
- form-data처럼 name 필드는 없음
- name 필드 구분없이 데이터 보내도 좋을 때 사용함
- ex) 파일 묶음 전송할때 좋음
- 예시
Content-Type: multipart/mixed; boundary=----Boundary123
------Boundary
Content-Type: text/plain
This is plain text.
------Boundary
Content-Type: image/jpeg
Content-Disposition: attachment; filename="image.jpg"
(binary data)
------Boundary-
- multipart/related
- 루트 데이터와 연관 데이터로 나뉨
- 루트 데이터는 연관 데이터들을 가져와서 완성된 루트 데이터를 형성함
- 예시를 보면, 루트 데이터인 HTML은 연관 데이터인 image 데이터를 가져와서 완성된 HTML을 만듦
- 예시
Content-Type: multipart/related; boundary="boundary123"; start="<main.html>"; type="text/html"
--boundary123
Content-Type: text/html
Content-ID: <main.html>
<!DOCTYPE html>
<html>
<body>
<h1>Hello, World!</h1>
<img src="cid:image1.jpg">
</body>
</html>
--boundary123
Content-Type: image/jpeg
Content-ID: <image1.jpg>
(binary image data)
--boundary123--
- multipart/form-data
- 위 글을 통해 HTTP Form Request에서는 multipart/form-data가 적절한 전송 방식인 것을 확인 할 수 있다.
- form-data로 Request 요청을 내리기 위한 예시는 아래와 같다.
- 예시 - FormData 객체 사용
var formData = new FormData();
formData.append("textField", "sample text");
formData.append("fileInput", fileInput);
var xhr = new XMLHttpRequest();
xhr.open("POST", "/upload", true);
//formData를 xhr에 넣으면 자동으로 Content-Type = multipart/form-data
//xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.send(formData);
예시 - HTML Form 사용
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="text" id="username" name="username"><br><br>
<input type="file" id="profile-pic" name="profile_pic"><br><br>
<input type="submit" value="Submit">
</form>
3. BE(Spring)
- 요약
- 이미지 전송 과정을 확인
- 설명
- 프론트로부터 이미지 파일 받기
- MultipartHttpServletRequest
- @ModelAttrubite
- MultiPartFile
- 이미지 파일 저장
- Base64
- Blob
- 프론트로부터 이미지 파일 받기
- MultipartHttpServletRequest
- Multipart/* 요청을 받기위해서 사용되는 타입
- 예시
- multipart/form-data 요청 시, 각 텍스트 및 파일을 받아올 수 있다.
@PostMapping("/item")
public ResponseEntity<String> item(MultipartHttpServletRequest request){
log.info("request : {}", request);
return ResponseEntity.ok("ok");
}
- @ModelAttrubite
- HTML Form 데이터를 보다 쉽게 받을 수 있는 어노테이션
- 사용 예시
@PostMapping("/item")
public ResponseEntity<?> item(@ModelAttribute ItemFormRequestDto itemFormRequestDto){
if(itemService.save(itemFormRequestDto) != null){
return ResponseEntity.ok("ok");
}
return ResponseEntity.badRequest().body("상품 등록에 실패했습니다");
}
- MultipartFile
- 스프링에서 이미지 파일 저장을 위한 객체
- 구조
- 파일의 이름, 타입, 크기 등을 담을 수 있음
public interface MultipartFile extends InputStreamSource {
String getName();
@Nullable
String getOriginalFilename();
@Nullable
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws IOException;
InputStream getInputStream() throws IOException;
default Resource getResource() {
return new MultipartFileResource(this);
}
void transferTo(File dest) throws IOException, IllegalStateException;
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
}
}
- 예시
- FE
- 이미지 전송
- FE
<form>
<label>상품 이미지 파일</label>
<input type="file" name="imageFile"/>
<button type="submit" className={styles.submitButton}>상품 등록</button>
</form>
- BE
- 이미지 받기
import org.springframework.web.multipart.MultipartFile;
public class ItemFormRequestDto {
...
private MultipartFile imageFile;
}
- Base64
- 각 0, 1의 조합을 글자로 해석하는 것
- 방법
- 주어진 바이너리 데이터를 6비트씩 분리
- 각 6비트의 10진수 값과 매칭되는 문자열을 도출함
- 인코딩 : 바이너리 데이터 → 문자
- 디코딩 : 문자 → 바이너리 데이터
- 예시
- 000000 = A
- Base64 ↔ HTML
- HTML에서는 Base64로 인코딩된 값을 디코딩하여 이미지 출력이 가능함
- 예시
- 해당 src 값은 Base64로 인코딩된 값
- HTML에서는 해당 값을 디코딩하여 이미지 출력
<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxMSEhUTExMWFhUWFhYZGRYXGBoYFRodFxgaGx0XFh0dHSggGB8lHRYYITEhJykrLi4uFx8zODMtNygtLisBCgoKDg0OGg8QFy0dHR0tKy0tLS0tLSstLS0tLS03LSstLS0tLS0tLS0tLSstLS0vLS03Ny03LS0tListKy8tLf/AABEIAOEA4QMBIgACEQEDEQH/xAAcAAEAAgMBAQEAAAAAAAAAAAAABQYEBwgDAQL/xABKEAACAQIDBAgDAwoEBAQHAAABAgMAEQQSIQUxQVEGBxMiYXGBkTJSoUKxwRQjM2JygpKy0fBjc6LhJDTC0hUlQ7MWNZOjw+Lx/8QAGAEBAQEBAQAAAAAAAAAAAAAAAAECAwT/xAAjEQEBAAIBAwMFAAAAAAAAAAAAAQIREgMhUTFBcQRhkbHh/9oADAMBAAIRAxEAPwDeNKUoFKUoFKUoFKUoFKUoFKUoFKUoFKUoFKUoFKwNsbVjw0faSHS4VVGruzaKiDixPCqTBt/aIxbM35Oyag4JJo2xCAakgfakGtxex3aaVm5SO3T6GXUls7a8+7YtKru1+kY/IfyvCvG4JQKzkBRmcK18zKAwue6zIL2BIqr4vrFxCQSyJhu1y4VJVdVIjD3mzdqM5yplhLAhiDlIDHMpOnKyy6rZVKoON6dyCXFRxotksIHMchDskqRTAnurJZpBYI1+417VkbO6Q4yY4WzQIJpp4mBicv8A8O0t2t235sssYGQ3KE6k2tRF2pSlApSlApSlApSlApSlApSlApSlApSlApSlApSlApSlApSlBTetCBRhVnsolimhMcjC+S8qXPloL+VV2GfB/ls3Z4VkxKCeXP3iI3shaWTNJYpbEK1hoM2gNr1s7F4RJVKSIrqbXVgGU21Ghrwk2TA2jQxnudnqinuXU5N3w3RdN3dHKsce+3ox69mExls1bv4uuyndGsO0eycNJh4z2jvhnl7PKHkUTL2l7kBiYww8ayMTLjc7ypFiC/aEpGTGMOYQmkbLm0YnS/xZje+SrhFhUVVRUVVW2VQAFFt1gNBX0wLy5f6SSPYk1qTU05dTPnncvNUERbSCrG4xBdI5wskbxWeRjE0TyXspAvKpBW3d3HSrZMktzbMWKncbKD2e9dbEZ/ANrvtUh+Rpa1tLMN53Obt7mv3JCrEEjcCPQ76rCPaKQXzZyNcoRiSDyZjYtzF9NSDwpDDKW797G9yHbeALADTKL31HKx31nJh1G4cAN54Cw+hr8nBpa2X7OTj8PK9BgpHIDH8Z7qXGY2vfvkm9t3Ajh3bGpavMQre9tf6C33G1elApSlApSlApSlApSlApSlApSlApSvKbEonxOq/tMB99B60qNk6QYRd+Jh0/xF/rWdBOrqGRgykXDKbgjmCN9B6UrB2tteHDKHnkCKTYX3k8gBqar+L6xcCqMyyFyFJChWFzwFyLC/M0FrllVRmYhQN5JsPc1B4rpngYzlbELcfKGYe6gitFbZ2/iMXI0ksjakkL9lRyUHQCozcbgm/nQdI7O6SYWc5Y5QSdwIK38swF6kcRiEjGZ2VRzYgD3NczQbSdN3DXTcQN+nA1n7U2jLiFUvIzZBYAsSAPC9Bu/FdNcBGbNiFv+qGb+UGs/Zm3MPiNIpVY77ag25gHePEVzWTWVhNpyQ95CdDf24jkfHfuq6HTdKpvV30lfFK8crZnQKytxZWuNeZBG/8AWFXKoFKUoFKUoFKUoFK+M1tToBUS3SjBhxH+UxZmIAAYHU6AXGg10oJelV7pH0ywuD0ds8lwDFGVaQXF7sL90W58xVYTrbh7QB8O6xkGzhlJ8O7p5HXSg2RStZ7V60A0LiGJkkYWRmKmxuASR4Ak8eFUTE9I8XIDnxU194s7KPIgG1B0PUV0g6RYfBKGnfLmvlUAlmtvsB5jU6a1p3or1mTwMqys00IFsrWL28GPeJHC5ItppoR96xdrflONYg3jREWPlZlDlvXOPQCguGJ61o98eHdhzZwvuADarZ0a6TQY1LxNZwO9G3xr4+I8Rp66Vz3/AEsfI8K/fRbazYLFxzXP5t7N+sjaMPG6m48QKo6A6X9IFwOHaVhdicsa/M5BsPIWJPlXP+NxssrtJJIzO5JY+J5chWwOtzayTfkyxSB1HaMcuovZQDfjoT71Tdl7FM6uyuAVv3banS413AGx14BSTQRiYgqdfQ/g39at3QzpucKwBJaFyM6fLfe6ciOI428iKnisMyEowKsOB3i4uPvBrAjkClhuG8euv4/SgsnSTbsuNmMshsNQicEXgB48zxPoKh5xoF9T6bh9al8HJAkKTAgMASbm9ipNyBu4XHnUXPjTiCJCxa4sGO+wJA4DlTaPKKBmNlUsdNACd5AH1IHmRX3F4Zo2KOMrDeD4i4+hvWds3aDwZstu8Bv3XVgyt6EXrKxWOnnUp2Ys2RQEj1FhmVVOrWsl9SdATzqKgjpry/s/SsjAOBdDw+62n0P0rLn2NMkRmdcqjLa5Fzm5Dw0ve2+oKGXvsfG3sAPwNBYJY4HjYxllkS2ZHsQw+ZDYeduQNRL1C4vGEMbOS1/EBQOGu/lUgmJumbwv7b6sF/6qMWwxcIXj2kbfshSfoUX2reVam6mtmHOZCP0UYF+GeU3NvIBv4hW1mlUEAkAncCRc+VQfulK1p0t61Vws0kUUSuY3KNmYgkjfYAbgdL3oNl0qL6M7X/K8LFiMuTtFvlve1iQdeIuKlKBSlKDnjZ/S+aEYjCsxMWIjYC5JKs2hKk7gRmFvFeWsRtIMI9NNMw04cbeGh9RWB0rmRXikRn+NsxZVXiDoFY348qmsTNCY8t5H7jAXYCMFhqyixOW+tu6TpexoI/BYsy6u2Z9zMxufs2JPlp6GvPpDhWS4bQoddbjXiPMW18qiei+KVZDnGZbC4zZb7+PDff0qd29iYjBIFiCEgWbOzEW4ctfKqGy2D4cPfVHyEeGUkG/sPSszE9nlQoxzW76kbiOIPEH6VUth414jmDZVDK2psLgghgOJFquY6QTXBzKDw/Np72y76CqNiFjmItcK+7gRe9vbSrLiLPI3ZC690rlu2gAXS3C4t56VScbJmldh8Offw/vSrTsnpAckUMK5XhWS8qk53EjAtcbrA2sBe3uaCdxWDlnfP2KxXuxJOQd4nvPmbS5BtuvY8qpe3CVnZc17WFwdDbS45jSpuWdnOZiWPNiSfc1VNozGV2cGyiy3/pz50I2ljthFdnYPElyVMeHzi3wrLGuoPGxsPWoybA4ezFcSDa9l7Nrk62F72tu18d1ReI6yJ3w64QLEIhGkYshvlQADUsd2UG9uFeKyaa29Nx8qCZlwEOV2/KlJAYhcrZmsGyi+7UBfK/hrR8bN+dbwsPoKlto49Y1vxO4c6r8sOhkkJBZtFG831NzwqC1S4aWFI0lVlzIkiq24rIMwYDdx9wRvFfjZ8xSTvd5cwcDS1gRmTda27hzqvNtqVjozAftE1JbLxi/FItze2cfENLf3+NUXCTbqgkx4aFbljcjMe9fy3XrDfbMxJbPYnLcgC/cBC62uLBiPEHW9Rs0qAZlcMvPiP2hvHnWFJtWL5ifJT/8Ayp2GfjccSt5HYgWvdid24C9V3CT53OoUXJJNyNTe2gNMTIZmF7qg3DifOvsMc0rFcPGcvw3RQByN2/3oG1VUsCup4kA2+oBvWTsGC57yTSAG/Zxpe/ixvoPC3CpTZXQKRrGWRUHyoMze5sB9at+z+iuHjXLlLcyx1PibWpsS3R/pxPFA8cWz1RQCVdnEdjl3uCWMjXHIbrVrPam1cROVJVjJxbvF2PMkmthf/D+DG+FL1ivsfCKQewQ2NxcXqQT+A6Yv2EUfaPJIsaKwjGZrgD434HxJqq7R2Es8jSPGELsWYu7M1zvJVSB9alWxZtlUWA3AaAeQryCMxq6H6w1oslpHOSxUZsqrbdYL+N6t/RTpJM06xSMXR7gE/EpAJ38Rpaxqu7J2O85tGpe2hI+EeZ3VeujnRfsHEjkM4HdA3Lfeb8TbT1NRVlpSlVHLm2OjGPy3fCTg2yr3GtdiN3id1YuF6PbQSJkbDYgDX/0nJF94+GuraUVx7iNgYktlTDzWUAHuNodTrpodQakZ9lYp0CyRTcLgRtbTxArrCvtBx3JsPEO2ZIJChtZghK2AtobeFScez8TkCvHMLC2gbd46V1eiACwFhyGgr9URx9jNmSlQkcTnKTeynQ+Pjvr84PY2IVg3ZuPMEV2BHCqkkKAWN2IABJ3XPPSv3QclYrByt8SyaeYHrz86wMZgZCqhI2IvfQaf3rXYZF9DXjhMHHEoSONEUXsqKFUX1NgBaiuO49ly/IfWpQYRsiggseItusdPPTjXWuQchTsxyHtRHI64CxuIzfyrG2hgpXIAjawH1P8AYrrbG7JgmKGWGNzG2ZCyBsrc1uNDWXkHIe1FcdxbDn+Q1YdmbGXIA6S5uNmW3p3TXUeUchX0CiOUZNjzXOWNiOB0/E14ybMlXQx5SebID/NXWtUzrIx+HhjRnijkxFz2LMqs0fN1JGnD1tyou2jNn7Ea95hYfLcEnzsdB9asWGkVAFUAAbgNAPSsCfEMxJJJJNyTqTXn2tNM1OjaFuNReO6RMTlU1EbTxuUWqN2fd3HMmqLns6Z24k1LNHYamvGDASx4WWaOO6xLd3Jso/VX5jruHra4vr3afSSaXQNlXw3n14VBc9pdIoINL5m5Cqtjul80ug7q8h+NVw1+8ONR50V0n1PIfyDMd7SN9FWrzVT6ro8uzovEsfrb8KtlApSlApSlApSlApSlApSlApSlApSlApSlAr5avtKD8SyBVLMQFUEkncABck1o3beOfGzviDfKTaMckX4R+J8Sa2J1nbRKYZcOh7+Jfs/HINXPtZf3qrkOygqgcqb0Ka2BNY0+Eyi5q9f+GjlVd6YqIYTzOgq8ka32pPdqtnVzsNsRKoXeToTuUDUsfIfUgcapJBZwOZro3qk2H2OG7UjvSd1f2V3n1a/oq1FZvTzCpBsfERoLKsQUczdluTzJJufOuX66h612tsrE+Sf+4tcuigGsjArdh514Vm7KS8i+dB1D0Aiy7Pw4/VJ92J/GrDUV0Ujy4PDj/Bj+qg/jUrQKUpQaCXrIx5iSLtQGVFXOFUs5A+2WB1PMW1qb6BdarmUw7QcZSDklC2KlQSVcKNQQNDbeLcdKNDsg9mDIQhy93NvZhvWwuVvY2vaocRETMTrmS4PkQD+FBvbF9a+CjcKVmy/PlUDzALBiPSrfsXa8OLhWeBw8bXsdQbjQgg6gg8DXMBjzKVbTkeR/pzrO6D9MMTgTMsBGV17ysLgMCAHUfNa48Ra+4UHT9K5u2l0pxmJ34mUP8quVVvICwU+W+s3oJ1jyYGTs8S7yYdj3sxLPGfmS+pHNfUa7yuhKVD7W6T4XDIrySizKGUIC7Mp3MAoJseZ0qrxdbGDL2Mcyp85C/UZrge9EbApUdsTbmHxkfaYeVZFBsSLgg2vZgbFTYg6jjUjQKUpQKUpQKUr8TSBVLHQKCT5AXoNZdJ8X221iu9MLEF/fk7zH2Kj0rPEutUTYu08xnxUht2srOTa+jNYC3hf2BqyxY0EXv/f4+dZVMqRWsOs7HXkWMHQDWrycbZSb8K090pxvaTO1+NIPnRTAmfEoqi5LADzYgD6kV1fgcMsUaRroqKqjyAtWheozZufFCQjRAzeoGUfVr/u10DWkU7rb/wDlc/7n861zOIxXSfXE1tmS+LIPrf8ACubloPyYhWfsZPzg8KwzUp0fjvKBzIHuag6o2ZFlhiX5Y0HsoFZVKVQpSlBzLjcYyDIwU2YNoNPDeSCPTWvHZESTOMxYMoPdFruNL947jpyrJ2iQYmuLlASvMjip+8cvWqrhi879mmgN7k62XiT6H62qi3bbdUbsfzYClShWxbvg3RmBOYgi+82v41XsNHlnkHBlDfX/AHqYk2OFUMSHC2OY+17cP71rB/L1jcOEV2Atdhpa/wBaaRlf+Eydn22U5M1r+e77jVe2jhyso/XI9ybH7/rVt2ntOF8sqtIbxEOCLDPcWUanQHj4LaofboGWN+Cup9KivWUt3Tc91VUak2CiwUeAAFvKvHE3lFibsNx5/qnmeVSuDwZlOm4as3BRzNfNpYBImASRZFIuHW9j4a7iDpaht4dCelUuzcR2i3aNrLLHe2dfDkwuSD5jcTW/Np9N8HDBHMZQwlQPGq6uwYXBt9kefI1zDtcFZSTrm1H9/wB76n2isuX5QAPTSoq+7c6ycbIT+ThI05p35LeJYafwjzrz2T1tzxWGIVZh/BJ7gZT7DzrX6MQbg2I4jfWPj4813G/7X/d/Wiunuje3ocdAs8Jup0IPxIw3o44EfUEEaEVKVzN0B6YPs6fPqYXsJkHEfOv6y8OYuONx0edoRdkJzIoiKhw5NlykXBueYIqoyqrnWLj+w2biXvYmMoOd5CE0/i+lVLpN1qqLpggpO7tZLgfuLpfzJHlWutt9I8ZiUKTzO6uy90nuEg30A0FrcKmzSx9Ddkxz9nBJfLlZyAbE5ABa+8ayA/u1+pYQpd8MsrYMWtKwNlNrsNQDkBJF+Bvrvv6dEcXEk6h2yOEXs2+wGYm4fX7Ssg9OBtVwixkvbLBFCIo49ZQwGRlfMAIraHXMTex01G+sihbUxhWFjxtWr8W9yavHTpuwleBPgDy5RyUdkVA8AXdR+yao0SZnUcyKsG++ozZ2TDySW3lE9gWP86+1bPqr9W2D7LARaWLlnPqxA/0qtWitIofXS1tmnxkUf6WrnRa6G67z/wCXr/nL/I9c81B9qw9C4s2KhXnNCPeRart6uvVlh8+Ow4/xgf4AX/6ao6SpSlApSlBz1iFiaNWQhXAs6G/e1tmU6jW+o0qsbIw/ZYiWPgVDD9m5/EirNhtqxSoueNWtYGVLrIQBY5hexbdqaitstGmJieMsUZShzgBgTY2NtDqB70i1mLu11B3jhrVc2rhOzbTdvB5jl5irrgcPG6Mjd2Uapc2DXykKb6bgbbr5xvqs9KMKxiOhBja5B0PIgjwoiI2VKWkEYF8+h5AfMeQHOrDLs8IgjZc9txcWXwsOI8yfKsboyoXDqQAC+Ys3E2ZgAfAD8amUxBtlNmXkdR5jlQRqbRkTTN3R9n7OnIDd6ViJjI7qij7Tkm/FiLAeAAt614bajYMflOq/0PjUUDxoM7bq6o3Jh/W30qaRQwGu+sDD7PbFhbMFCnvk6nUaZV439B7VY4IVhChb3W1idW0+70qVX4n6PL2RcTL2ijM0JBDgcSL/ABW47vC9QRTSs+edRNHIzFiuYuRvNxYDXx18qxUII3i9qhFYdrOQedWjE7anlghhdz2cMaqiblAA0J5m2l6ru14vzotxH3af0qaK/wBPaqrBesjZ8eZtTYLdjYXO8AWHMlgPWvv5MWNlBJPAC59KyMFCU7QMCCCqkHQ/aYi3mi1Mrqbb6ePPOY+a2X0NwqZY5h3Xk7QWbUPGpCZPNezDeIvzNpDbe3IEcwT9rCbXSVL7jxUrqNRYgi2nGo7YWyCmEKyyWDMjxspN42YLZhyIY+W/majOkGME8LQzgJjICMvyy5iB3f2rg28ARxAjF1vs1z0gnLSakkiNL3NzmfNKSTxP5wa+FY/R+HNOvhrXntOUPLKwNwZHyn9VTlX/AEqKsnVjgO1xaC2hdB6Zhf6XqwrpLZWG7KGKP5I0X+FQKyqUrTLXfXef+CQc5R/I39a5+YVv7ruP/CxDnI30X/etBS76g/A31sXqjhvj4DyMh/8AtsPxrXUe8VtvqUgviiflhc+7IPxNUbspSlApSlBofpJ1dYjZ7NLBmxGGOrAC8qeJUfFbmOG8CqXtnFI6KEIvmvc3GXz0rqyqD036sMNjc0kVoJzqWA/Nuf8AEXn+sNfOg11s7aMcsarOL5VCiSOwcWAsrad8AAWvqBXzHYFyuZrukgPf3g3Gt99iOR10qv4nY2J2ZOY8ShVXPxb4zbcyNuPiN/tU3hMe6BgjGzqQQNVYMLeu/Q0VGbIjywhOKM6n+I/hapQYVggktdTfUEG1jaz2+E6jfvzCorYDIcZJDI2RXYnNyO4nX930B3VbIMZLhV7GVA0TK1sp3iQC5VhdWvlG8E6aWomkBjMMJEKn0PI1SsVLkYrxBIPKr/jYAjDK4dSMwYb7EkWYfZbTUVRulGHyzE8HGb14/WisrojiXGIuFZlKkNbQDS4J9QPrVuk74Klgpv8AKLaX0+Yb/wC9KgejIy4ZSNCzOSeJscv/AE1IFqlHhitmsutrj5hqP9qiZ5cnnU8k5HE1CbWwtjmHwn6UNMCSTMQW4casm0tnGJ1QMJMyIysmofMu9eYvf2qrCp/o9tSxWKRrIdAx3pc3yg8FJPub86gldnt+TB5WJDBbALqdSNCeG4VhxM012OrzSufMtlAty1LCsnbeJQAot9OA582PHyr5sbCZ5IIs+QkCz8AWzOvr3lG/fWc/TTt9P2z5eJf02Av5UI+1SPLIukkB1jlsB34iDoSOW/cQbCq70l2zh50ScBlniJLIRrlRWkNzuYAp5jMdNak9n47FMJcI8mXEoVaNmt3wpuVJt3gQN/EE8qhes+BIwWVQJJIrPbcS7pGDbgbM+vGwquLWIFlUcgK2v1H4C84f5Q7fTL971qmQ61v7qVwOWF3t9lFHrcn7lrRWy6UrzxE6xqXchVUXJO4AVUa567D+Zg/ak+irWg5jc1snrH6YHFzARi0cd8txe/MkHTWw9hVHPZt8UY80OQ/cQfaoqOgHeFbq6kYfzkrcowPdv/1rT7QorLkYnXcRYj1Ghrd/UnH3J2/yh/PRGzaUpVClKUAUpSgxNp7NixEZimjWRG3qwuPMcj4itRdK+rPEYYNJs5jJHqexaxkTxjJ+L7/Ot0UoOQ4NqSQs2ZbuL3DCzX4hr6irrsfbhCCwDxNZjG4BGm+1/hOpGlbb6ZdAcJtEEuvZzW0mQDN++Ptjz9601tToritluVnXNAx7syAlAf1uK34g8tKKkxs7tVzQEMQBeO57QWXvNY7xdSdCd9VbpbhCYgxBDI24ixs39/WpjDTlSHRrEaqyn6qRWJ0vxrSRs76s5UE7r5VC387ChXhsS35NFbgGv552v9az8LhXlYrGjOwBayi5sN5txqD6IS5s0J0uwKk3t3rKTu3AgbvmNWnDj8kxI7aMP2baqDYHTRgeO8H6GgiWNHswyncatW11jxUIeHKZUJumUJKygOzsVGh3K282zML1VGUgkEEEaEHQg+PKoIDH4YxtY7uBrGYGpnbsV0VvlNj5Hd9aifs0EthIC0SuGvclSpGuYXOh9Bw9anIdnPIZDGtxEtzbflU5RbnYD2BqE6OsdR9kMH9hc/RKunRPaS4eLEPvfKmW98psSMt+d3GnLyrGXrI9HTlnTzy+J+b/ABlbFxaY3so5myzxMpjlG91UglCedgdfXnet9ZblZmQyM/5xLZrXCpGWKacA0qedWRkjSSPaGHXNFc9pGPijZgVa3D7XlqOB0onTfHCXEFhuPaOOf5xyo8u5CnvWnnV/CpmdRzIrp/q4wnZ4Jf1mJ9rL/wBNc3dGoc+IQcjf2rqDZM8eHwUbswyrEpJBBFyLkDnqTVhUu7hQSSAALkncAOJrTXWF0yOJYwxE9ip/jI4nw5Cvx0q6ZzYpmjjYrEfsC12A58T71SZJRrVRiYusFvrWbiCK+4PCkm/E7vCivuzNn5j95rdnVBEBh5WG4yAeyj/urUW0phEBCvxMLueQ+X1+7zrcvVElsCTzlY/6UH4URdqUpQKUpQKUpQKUpQK854VdSrqGUixVhcEciDvr0pQaw6U9WRXNLs4hTvOHfWMnnGfsnw3VpfbM+LilKThlZT8BGUjysNfOut6hek3RbDY9Mk8YJt3XGjr5H8KDlhdtHto2YnKoKtzs28+NrKf3a2JBt7OojxI7WMlTn3yKB8rcbi2twTbeai+m3VhicFeSMGaD5lHeUfrrw86gNhYvTsm4fB/2/wBPUcqirjiNlro+Gm7T84iqPhcGRpAlySLH834bwdBUXtLEvLI0j2zEi9hYXUBd3DdX4hmZSCpIIIPqCCPOxANTeHxWGnss6CFi5JljGneU3zA3Or2PIcMooK/NF2iMvzAj14fUCqzEef8AZFX3amxjB2Zzq4kJysl7d3Kd+46ON1+Na+2w+WWRRuzH/ekFj2FH3DbUuXsOdhYgemf2q+7L2gMPgELRZ1aRlddws2Y3sRY6WFUXBw5Rhl+VQ58wO0NbJ2bhs2C7PEoVC3ja+hCqe7J+6ePIXqWd9tc7w4/faAxEpwUgkh7+GxCEhTuII1U34rfjwNuda42295pBf4Sqf/TRVP8AqDVtnaWxuywPZu4fLOpQjSwdgtv9TE+daamlLkud7lnPm5LfjRmJzol3O1mO5EY+wv8AhWbsza7nD9nYLc5msTYnyJ/u9YmCTJgZTxkKr7nX6Xrzwi2FaR+sfOy5WUkEE6jyqKhxzXObdx5+AHiTUxMRbXdxvuqNwkHaNmAsvD/uPnwoMnZ8DMcz8eHAW3AVYktBGZWHeOijma+bKwYPebRV/ConbGO7V77lGijw5+tFYBkLSMxNydSfOuheqcf+XIebyfzW/CudYT3jXSXVhHl2Zh/ESH3kc/dRFppSlApSlApSlB8FfaUoFKUoFKUoPhFa96Z9V0GKvLh7QTb9P0bHxA+E+IrYdKDm3aWDlwr9li4zE/B//TfxvuHnu31+MhH9/WuiNq7KhxMZjmjV1PAjd4g8K1F0q6tsVhA0mz3MkWp7FgCy/s331FVkMQLm+VMzWN7AkcuF7D2qiT4Z3kUFSO1cAEjfmYDT3rLxO1MSrFZGY23qe6R6AC9ZOwMS2IxkQPwx5nt+ypNz62qlXHZ2H7TGAcMyL7sLj+BXrYc2MCyLHKcuY3RvsPcEGN+Ta7uOhGula22biSsuddWV1fLxYLe4XxsTpxBPKrTPKDKYJbth8UQ8L78rPbdy1O7xHAmpUQHTGCTDiSPO/Y9nI0YLHKMylAByKs4HtzrXLjhV36avMiGGZsxUoinmpPaXvx/Qjfrwqm4ZMzqOZFRVjxy5MPAnMlvYW/6qwkNZnSaTLIi8FQD13n7xUFisVfuKdTvPIeHjWkes7mVsg+AHU/MR9nyHGpvZ2DuQo9TWBs2AAAAeAFbE6FdHTPIE3KLNIw4LyHidw9TwoK5t5jEix2sGXNfmLkaeFwfaqhNNrWxOuxgmLVVFgsEYAG4AFrAVqmWagzsM17nxrqHoJHl2dhB/gof4hf8AGuV8E2hrrbo9FkwuHX5YYh7IKCQpSlApSlApSlB8r7SlApSlApSlApSlAr4a+0oOceuP/nT5v961Xuhf/MN/kSfelKUi1MYT9NH/AJifzCr9s7/l8N/n/wD5HpSslU/rN/St+3H/AOy1U/ZH6ZP2hSlD2SPSz9MfM/ypUDB8bftV9pWkWnZH6Ra3T1afo5v8wfyilKo1v17f84P8pPvatUtSlQZeD3e9de7N/Qx/sJ/KKUoMmlKUClKUH//Z">
- 장점
- 이미지를 온라인으로 불러올 필요없이 바로 출력
- 단점
- HTML에서 데이터 크기가 33% 증가
- 이유
- 가정
- HTML에서 문자 1개는 8비트
- 바이너리 데이터 24bit가 주어짐
- HTML에서 바이너리 데이터를 그대로 옮기면 3개의 문자임
- 8bit 문자 3개
- 하지만 Base64 인코딩 하면 4개의 문자임
- Base64는 6개의 비트를 사용함
- 따라서, 24bit면 4개의 문자를 만들 수 있음
- HTML에서 4개의 문자로 표현되니 32bit로 표현되버림
- ⇒ Base64 인코딩 과정을 거치면서 데이터 뻥튀기
- 가정
- Blob (Binary Larage object)
- 요약
- 바이너리 데이터를 다루기 위한 객체
- 설명
- 사용자 정의 바이너리 데이터 저장 객체
- 각 플랫폼에 따라 바이너리 데이터를 어떻게 다루느냐에 따라 Blob의 기능이 다를 수 있음
- Blob으로 데이터 저장
- 바이너리 데이터를 그대로 저장함
- 따라서, Base64와 같이 데이터 크기가 증가하는 일이 없음
- 예시
- GCS
- Blob
- 바이너리 데이터를 꺼냄
- Blob
- GCS
- 요약
package com.google.cloud.storage;
public class Blob extends BlobInfo {
...
private final StorageOptions options;
private transient Storage storage;
public byte[] getContent(BlobSourceOption... options) {
return this.storage.readAllBytes(this.getBlobId(), Blob.BlobSourceOption.toSourceOptions(this, options));
}
...
}
- BlobInfo
- Blob의 데이터에 대한 정보 표기
package com.google.cloud.storage;
public class BlobInfo implements Serializable {
...
private final BlobId blobId;
private final String generatedId;
private final String selfLink;
private final String cacheControl;
private final List<Acl> acl;
private final Acl.Entity owner;
private final Long size;
...
- 이미지 전송 및 저장
- MultipartFile (이미지)의 바이너리 데이터를 BlobInfo 및 BlobId를 통해 타입 표기
- 해당 이미지 바이너리 데이터를 GCS에 저장
public String uploadImage(MultipartFile image){
if(storage == null){
log.info("Storage 생성 실패");
return null;
}
String uuid = UUID.randomUUID().toString(); // Gcs 에 저장될 파일 이름
String ext = image.getContentType(); // 파일의 형식 ex) JPG
// Gcs 이미지 업로드
BlobId blobId = BlobId.of(bucketName, uuid);
BlobInfo blobInfo = BlobInfo.newBuilder(blobId)
.setContentType(ext)
.build();
try (WriteChannel writer = storage.writer(blobInfo)) {
byte[] imageData = image.getBytes();
writer.write(ByteBuffer.wrap(imageData));
} catch (Exception e) {
log.error("이미지 전송 실패");
return null;
}
return createURL(uuid);
}
QnA)
1) 이미지 파일을 JSON 방식으로 보낼 수 있나?
- 의문
- FE → BE으로 이미지 파일 전송 시, multipart/form-data의 content-type으로 데이터를 종합적으로 전송한다.
- 그렇다면, 이미지 파일을 JSON 타입으로 보낼 수 없을까?
- 결론
- 이미지를 바이너리 데이터 형식으로 JSON 전송을 할 수 없다
- 이미지를 Base64 인코딩된 문자열 형식으로 JSON 전송을 할 수 있다
- 이미지를 바이너리 데이터 형식으로 JSON 전송을 할 수 없다
- 요약
- JSON은 텍스트 기반이므로, 바이너리 데이터 형식으로 데이터 전송 불가
- 설명
- JSON 데이터를 읽는 데는 4가지 타입을 지원
- 문자열, 숫자, bool, 객체
- 바이너리 데이터 형식대로 데이터를 보내도, 읽을 수 있는 타입이 없음
- 따라서 바이너리 데이터 형식으로 데이터 전송 불가
- JSON 데이터를 읽는 데는 4가지 타입을 지원
- 요약
- 이미지를 Base64 인코딩된 문자열 형식으로 JSON 전송을 할 수 있다
- 요약
- Base64로 인코딩된 값은 문자이므로, JSON으로 전송 가능
- 예시
- FE
- image → Base64 인코딩
- Json 형태로 인코딩된 image 값 전달
- FE
- 요약
import React, {useState} from 'react';
import styles from '../css/login.module.css'
import Cookies from 'js-cookie';
import {Link} from "react-router-dom";
const Image= () => {
return (
<div>
<ImageForm/>
</div>
);
};
const ImageForm= () => {
const BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8080';
const TEST_ENDPOINT = '/test';
const [base64Image, setBase64Image] = useState("");
// image -> Base64 인코딩
const handleImageChange = (event) => {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
setBase64Image(e.target.result);
};
reader.readAsDataURL(file);
}
};
const handleSubmit = async (e) => {
e.preventDefault(); // 기본 폼 제출 방지
try {
console.log("image : ", base64Image )
// POST 요청 보내기
const response = await fetch(`${BASE_URL}${TEST_ENDPOINT}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ image: base64Image }),
});
if (response.ok) {
alert('조회 성공' + response.text());
} else {
alert('조회 실패');
}
};
return (
<>
<form onSubmit={handleSubmit}>
<div className={styles.heading}>로그인</div>
<input type="file" id="imageInput" accept="image/*" onChange={handleImageChange}/>
<img id="preview" alt="Preview Image"/>
<input type="submit" value="제출" className={styles['submit-button']}/>
</form>
</>
);
};
export default Image;
//image 예시
//image : data:image/jpeg;base64,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
- BE
- String으로 인코딩된 image값 전달 받기
@Slf4j
@Controller
public class TestController {
@PostMapping("/test")
public ResponseEntity<?> test(@RequestBody Dto dto){
log.info("dto : {}", dto);
return ResponseEntity.ok("ok");
}
@Data
static class Dto{
String image;
}
}
//dto 출력 예시
//dto : TestController.Dto(image=data:image/jpeg;base64,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)