multipart - woowacourse-teams/2023-fun-eat GitHub Wiki

multipart

โ€˜ํŽ€์ž‡โ€™์—๋Š” ํŽธ์˜์  ์Œ์‹์„ ๋จน๊ณ  ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํผ์ด ์žˆ๋‹ค.

์‚ฌ์šฉ์ž๋Š” ๋ฆฌ๋ทฐ์— ์‚ฌ์ง„, ๋ณ„์ , ํƒœ๊ทธ, ๋ฆฌ๋ทฐ ๋‚ด์šฉ, ์žฌ๊ตฌ๋งค ์˜์‚ฌ๋ฅผ ๋‚จ๊ธธ ์ˆ˜ ์žˆ๋‹ค.


์ด ๊ณผ์ •์—์„œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ผ ๋•Œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค.

์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š”์ง€ ์•Œ์•„๋ณด์ž.


๐Ÿ“ File Upload

์ด๋ฏธ์ง€๋Š” File ํ˜•ํƒœ์ด๋‹ค.

<input ref={inputRef} type="file" accept="image/*" onChange={handle} />

๋ณดํ†ต ์œ„์˜ ํ˜•์‹์ฒ˜๋Ÿผ input type์„ file๋กœ ์ฃผ๋ฉด ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ ‡๊ฒŒ file์„ ์„œ๋ฒ„๋กœ ์ „์†กํ•˜๋ฉด ํ•ด๋‹น file ๋ฐ์ดํ„ฐ๋ฅผ multipart/form-dataํ˜•ํƒœ๋กœ ๋ฐ›๊ฒŒ ๋œ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ƒ๊ฐํ•˜๋Š” โ€˜ํŒŒ์ผ์ด๋ฆ„.ํ™•์žฅ์žโ€™ ํ˜•์‹์ด ์•„๋‹Œ ์ด์ง„ ๋ฐ์ดํ„ฐ ํ˜•์‹์œผ๋กœ ๋ฐ›๋Š”๋‹ค.


๐Ÿ“š FormData

์ด์ œ File ํ˜•ํƒœ์˜ ์ด๋ฏธ์ง€์™€ ๋‚ด์šฉ์„ ํ•œ ๋ฒˆ์— ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๋ณด์ž.

์ด๋•Œ, formData ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.


formData๋ž€ form ๋ฐ์ดํ„ฐ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.

append()๋ฅผ ์‚ฌ์šฉํ•ด ๋‚ด์šฉ์„ key์™€ value ํ˜•์‹์œผ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.


formData.append('image', reviewImageFile, reviewImageFile.name);

์ด formData๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ multipart/form-data ํ˜•์‹์œผ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.


๐Ÿง‘โ€๐Ÿฆฒ Content-type: multipart/form-data

form์— ๋‚ด์šฉ์„ ๋ชจ๋‘ ์ž‘์„ฑํ•˜๊ณ  ์ œ์ถœ์„ ๋ˆŒ๋Ÿฌ๋ณด์ž.

์ž‘์„ฑํ•œ ๋ฐ์ดํ„ฐ๋“ค์€ Body์— ๋„ฃ์–ด HTTP Request๋กœ ์„œ๋ฒ„์— ์ „์†ก๋œ๋‹ค.


์ด๋•Œ, Body์˜ ํƒ€์ž…์„ ๋ช…์‹œํ•˜๋Š” ๊ฒƒ์ด Content-type Headers์ด๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ form์„ ์ „์†กํ•˜๋ฉด Content-type์€ application/x-www-form-urlencoded ์ด๋‹ค.


๊ทธ๋Ÿฐ๋ฐ ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ์ง€๋ฅผ ๋‚ด์šฉ๊ณผ ํ•จ๊ป˜ ์ „์†กํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ฏธ์ง€๋Š” file ํ˜•ํƒœ์ด๊ณ , ๋‚ด์šฉ์€ json ํ˜•ํƒœ๋กœ ๋‘˜์˜ Content-type์ด ๋‹ค๋ฅด๋‹ค.

๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์˜ HTTP Request Body์— ๋„ฃ์–ด์•ผ ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์„๊นŒ?


์ด๋•Œ, multipart ํƒ€์ž…์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

multipart๋ž€ ๋‹ค์–‘ํ•œ ํ˜•ํƒœ์˜ ์ฝ˜ํ…์ธ ๋ฅผ ํ•จ๊ป˜ ์ „์†กํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.


๊ทธ๋Ÿผ, Content-type์„ multipart/form-data๋กœ ์ง€์ •ํ•˜๋ฉด ๋ ๊นŒ?


๐Ÿšจ ์—๋Ÿฌ ๋ฐœ์ƒ

์›์Šค. ์•„๋‹ˆ๋‹ค.

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-08-06 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 3 05 35

์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.


์™œ ์ด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ?

๊ธฐ๋ณธ์ ์œผ๋กœ formData์— ํŒŒ์ผ์ด ์žˆ์„ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ž๋™์œผ๋กœ boundary๋ฅผ ๋ถ™์—ฌ์ค€๋‹ค.


แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-08-03 แ„‹แ…ฉแ„’แ…ฎ 4 40 32

๊ทธ๋Ÿฐ๋ฐ Content-type์„ ์„ค์ •ํ•ด ์ฃผ๋ฉด ์ด๊ฒŒ Override ๋˜์–ด boundary๊ฐ€ ์‚ฌ๋ผ์ง€๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ ์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค.


๊ทธ๋ ‡๋‹ค๋ฉด Content-type์„ ์•ˆ ์ ์œผ๋ฉด ํ•ด๊ฒฐ๋ ๊นŒ?


๐Ÿšจ ์—๋Ÿฌ ๋ฐœ์ƒ2

์›์Šค. ์•„๋‹ˆ๋‹ค.


แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-08-06 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 3 05 46

์ด์   ์ด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.


์™œ ์ด๋Ÿฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ?


formData๋ฅผ ์ „์†กํ•  ๋•Œ, ์ด๋ฏธ์ง€ ์ด์™ธ์˜ ๋‚ด์šฉ์€ JSON.stringify ์ฒ˜๋ฆฌ๋ฅผ ํ–ˆ๋‹ค.

const ๋‚ด์šฉ = {
      rating,
      tagIds,
      content,
      rebuy,
    };

const ๋‚ด์šฉjson๋ณ€ํ™˜ = JSON.stringify(๋‚ด์šฉ);

์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ, ๋ฐ์ดํ„ฐ๋Š” ๋ฌธ์ž์—ด ํ˜•ํƒœ์—ฌ์•ผ ํ•˜๊ธฐ์— ๊ฐ์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ธ์ฝ”๋”ฉ ํ•œ ํ›„ ์ „์†กํ•ด์•ผ ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ JSON.stringify() ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ–ˆ๋‹ค.


์—ฌ๊ธฐ์„œ json ๋ฐ์ดํ„ฐ๋ฅผ application/json ํƒ€์ž…์œผ๋กœ ๋ช…์‹œํ•ด ์ฃผ์ง€ ์•Š์•„ octet-stream(8๋น„ํŠธ ๋‹จ์œ„์˜ ์ด์ง„ ๋ฐ์ดํ„ฐ)์œผ๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค.


์ด๋Š” 'Blob(Binary Large Object)'์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

Blob์€ ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ ๋ฐ”์ด๋„ˆ๋ฆฌ ํ˜•ํƒœ๋กœ ํฐ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

์•„๊นŒ JSON.stringify()ํ•œ JSON ๋ฌธ์ž์—ด์„ Blob ์ฒ˜๋ฆฌํ•ด ๋ณด์ž.


const jsonBlob = new Blob([๋‚ด์šฉjson๋ณ€ํ™˜], { type: 'application/json' });

Blob ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด JSON ๋ฌธ์ž์—ด์„ ์ด์ง„ ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜ํ•ด ์ค€๋‹ค.

type์— application/json ์„ ๋ช…์‹œํ•˜์—ฌ ๋ฐ์ดํ„ฐ๊ฐ€ JSON ์œ ํ˜•์ž„์„ ์•Œ๋ ค์ค€๋‹ค.


์ด๋ ‡๊ฒŒ Blob ์ฒ˜๋ฆฌ๋œ ๋‚ด์šฉ์„ formData์— ๋„ฃ์–ด์ค€๋‹ค.


formData.append('reviewRequest', jsonBlob);

๊ทธ๋ฆฌ๊ณ  body์— formData๋ฅผ ์‹ค์–ด POST๋กœ ๋ณด๋‚ด๋ฉด


const response = await fetch(url, {
        method: 'POST',
        body: formData,
        credentials: 'include',
      });

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-08-06 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 3 06 28

์ž‘์„ฑ ์„ฑ๊ณต!!!

โš ๏ธ **GitHub.com Fallback** โš ๏ธ