내가 맡은 페이지, 기능부분에서 일어난 이슈가 아니라, 다른 팀원한테서 일어난 이슈이지만, 디깅과, 해결해볼 가치가 있다고 판단을 했었다.
공모전 포스팅들 중에서 서울시 데이터 통신을 할 때 http
프로토콜로 인해 mixed content Error
가 발생했는데,
우리측, 서버 프로토콜도 http 이다. http
프로토콜을 사용한 이유는 백엔드에서 나름의 이유가 있어서 http
를 사용했다고 하는데....
해결 방법은 우리측에서 multipart/form을 api router
로 우회하여 서버와 통신하는 방법을 선택했다.
그렇지만
여기서 새로운 사실을 알게 되었다.
실제로 팀원분의 terminal을 통해 확인했는데, form에 들어가 있는 파일 객체가 보이지가 않는다.
const Binary = () => {
const method = useForm();
const submitForm = (value: FieldValues) => {
console.log(value); // {text: 'asd', image: FileList}
const _File = value.file[0];
const result = await axios.post("/api/binary/handler", {
...value,
file: _File,
});
console.log(result.data) // { text: 'asd', image: { '0': {} } }
};
return (
<form onSubmit={method.handleSubmit(submitForm)}>
<input type="text" {...method.register("text")} />
<input type="file" {...method.register("image")} />
<button type="submit">제출</button>
</form>
);
};
터미널 창에서도 { text: 'asd', image: { '0': {} } }
이렇게 빈 객체만이 보여서 의아했지만, multPart/Form을 보내는 것이므로 (text 뿐만 아닌 이미지와 같은 파일도 보낼 수 있게.)
File API를 사용하면 웹 애플리케이션이 파일과 그 콘텐츠에 접근할 수 있습니다. mdn
File API는 웹 페이지에서 Javascript
가 조작 할 수 있도록 제공하는 웹 API이다.
즉, 웹에서만 있는 개념이다. node에 있는 개념이 아니다.
File 객체는 Blob의 한 종류로, Blob을 사용할 수 있는 모든 맥락에서 사용할 수 있습니다 mdn
File 객체도 Blob의 하위 인스턴스라는 말인데, Blob이란?
Blob(Binary Large Object)를 의미하며, 일련의 데이터를 처리하거나 간접 참조하는 객체이다.
-> 데이터 자체라기 보다는 데이터를 간접적으로 접근하기 위한 객체이다.
Blob은 웹에서 사용되는 데이터 형식으로, 이진 데이터
를 나타내며, 텍스트, 이미지, 오디오, 비디오 등 다양한 형식을 지원하고, 주로 파일 업로드, 미디어 처리등에 사용된다.
따라서, File 객체는 로컬 파일을 참조하는 Blob객체이다.
로컬 파일을 읽거나 쓸 수 있다.
이진데이터란 컴퓨터가 이해 할수 있는 데이터이다. (메트릭스에서 보던 0과1의 세계관) 이 중에서
base64는 이진 데이터를 텍스트로 표현하기 위한 인코딩 방식 중 하나이다. (다음 포스팅에서 써먹을 text형식의 인코딩)
클라이언트 측 ( 브라우저 ) 에서는 파일 객체가 File
또는 Blob
객체로 표현되어 File API
를 통해서 자바스크립트가 접근하여 파일을 읽거나 한다.
그렇지만
서버 측(Node.js)에서는 File
이나 Blob
객체가 존재 하지 않는다. 그렇기에 서버측에서 파일객체를 다룰 때 사용하는 버퍼(Buffer)
형식으로 처리한다.
그렇기에 node.js로 보냈을 경우 빈 객체가 있는것이다.
서버와 브라우저 둘다 자바스크립트를 쓴다고 객체가 자유롭게 이동되는 것이 아니다.
브라우저에서 서버로 보내는 Request body를 어떻게 구성하고, 어떤 데이터 타입인지 명시해줘야 한다. 단순히 JSON형식으로만 주고 받지 않으므로
첫 번째로는 URL.createObjectURL()
인자로 File객체를 받으며, 해당 file의 고유 URL 정보 생성 및 반환한다.
두 번째로는 FileReader
로 File객체에 있는 실제 데이터를 읽을 수 있다.
FormData를 보내고 싶으면, 헤더에 Content-Type: multipart/form-data
를 명시해주고, Web APis의 FormData를 사용하여 보낸다.
잠깐 formData를 설명하자면
HTML에서도 폼 데이터를 다룰 수 있지만, 자바스크립트에서 폼 데이터를 다루기 위한 Class instance이다.
자바스크립트에서 폼 데이터를 다루기 위함 이란, 이미지 같은 멀티미디어 파일을 보내거나, 할 때 사용한다.
const submitForm = (value: FieldValues) => {
const formData = new FormData();
Object.entries(value).forEach((item) => {
if (item[0] === "file") formData.append(item[0], item[1][0]);
formData.append(item[0], item[1]);
});
// formData = { text: string, file: File }
const result = await axios.post("/api/binary/handler", formData);
위와 같이 formData
객체에 넣어 요청을 보내면, 브라우저가 보내는 HTTP 메시지는 인코딩되고 Content-Type 속성은 multipart/form-data로 지정된 후 전송하게 된다.
FormData를 생성하지 않고 보내는 방법중에 axios
에서는 postForm이라는 메소드를 가지고 통신해도 똑같은 결과가 나온다고 한다.
const submitForm = (value: FieldValues) => {
// value = { text: string, file: File }
const result = await axios.postForm("/api/binary/handler", value);
따라서, new FormData()
, axios.postForm
을 사용해서 Form데이터를 다루면 된다.
header의 Content-Type : multipart/form-data || Content-Type: application/x-www-form-urlencoded
둘중 하나로 axios에서 formData를 보내 줄 때 지정하는데 뭔차이인가?
-> https://velog.io/@shin6403/HTTP-multipartform-data-%EB%9E%80
//여기서 이해를 했다.
Content-type: application/x-www-form-urlencoded
multipart/form-data
: 모든 문자를 인코딩하지 않음을 명시한다.<form>
요소가 파일이나 이미지를 서버로 전송할 때 주로 사용한다.Content-type도 타입을 하나만 명시할 수 있지만 multipart/form-data로 여러가지 타입으로 보낼수 있도록 명시해준다.
브라우저와 서버간, 리액트, vue, nextjs, axios와 같은 라이브러리 프레임워크와 상관없이 동일한 규칙을 통해서 서로 통신한다.
그 통신 규칙을 프로토콜이라 부르고, 웹서버와 브라우저간 사용하는 프로토콜이 HTTP이다.
Form 데이터를 통신 할 경우, form의 Content-Type은 json이 아니기에, 어떤 Content-Type으로 request 메세지를 구성해야하는지, request body를 구성해야 하는지를 잘 알아야 한다.
뿐만 아닌 서버에서는 이런 request를 받았을 때, 어떻게 해석하여 서버 로직에 쓰는지도 알 필요성이 분명하다.
브라우저와 서버 둘다 자바스크립트를 사용한다고 객체가 자유롭게 이동되는 것이 아니라는 것을 알게 되었다.