Axios: Axios๋Š” ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ๋กœ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2018๋…„ 01์›” 25์ผ  ยท  46์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: axios/axios

axios๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ ค๊ณ  ์‹œ๋„ํ–ˆ์ง€๋งŒ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. chrome dev ๋„๊ตฌ์—์„œ๋Š” ์š”์ฒญ์— ์ฝ˜ํ…์ธ ๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐํŽธ ๋ฐฐ๋‹ฌ๋ถ€ API ์‘๋‹ต์„ ํ†ตํ•ด ๋™์ผํ•œ ์š”์ฒญ์„ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
js (newData) => { const data = new FormData(); data.append('name', 'raphael'); data.append('file', { uri: newData.image.path, type: 'image/jpeg', name: 'teste' }); return axios.post(`${constants.development.URL_API}/file`, data, headers: { 'Content-Type': 'multipart/form-data', }, })`

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด ๋ฒ„๊ทธ๋Š” ์ตœ์‹  axios์—์„œ ์—ฌ์ „ํžˆ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์™œ ์ด๊ฒƒ์ด ๋‹ซํ˜”์Šต๋‹ˆ๊นŒ?

๋ชจ๋“  46 ๋Œ“๊ธ€

@corujoraphael ํ˜ธ๊ธฐ์‹ฌ์—, ์ด ์š”์ฒญ์ด ๋” ์ผ์ฐ ์ž‘๋™ํ–ˆ๋‚˜์š”?

@corujoraphael ๊ท€ํ•˜์˜ ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์‹คํ–‰๋˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ—ค๋”๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ตฌ์„ฑ์€ ๊ฐ์ฒด์—ฌ์•ผ ํ•˜์ง€๋งŒ ์ค‘๊ด„ํ˜ธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

(newData) => {
  const data = new FormData();
  data.append('name', 'raphael');
  data.append('file', {
    uri: newData.image.path,
    type: 'image/jpeg',
    name: 'teste'
  });

  return axios.post(
    `${constants.development.URL_API}/file`,
    data, 
    { 
      headers: {
        'Content-Type': 'multipart/form-data',
      }
    },
  )
}

์ด ๋ฌธ์ œ๋Š” ์‘๋‹ต์„ ๋ฐ›์ง€ ๋ชปํ–ˆ๊ณ  ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ •๋ณด์— ๋”ฐ๋ฅด๋ฉด Axios ๋ฒ„๊ทธ์ฒ˜๋Ÿผ ๋ณด์ด์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ๋ฌธ์ œ๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ๋””๋ฒ„๊น…์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ง€์›์ด ํ•„์š”ํ•˜๋ฉด Stack Overflow , Gitter ์— ๊ฒŒ์‹œํ•˜๊ฑฐ๋‚˜ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด ๋‹ค์‹œ ๋Œ“๊ธ€์„

๊ฐ์‚ฌ ํ•ด์š”!

@emilyemorehouse , React Native FormData๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ๋ฌธ์ œ๋ฅผ ๋งŒ๋‚ฌ์Šต๋‹ˆ๋‹ค.

let s = JSON.stringify({ uri: localUri, name: filename, type: type });
let formData = new FormData();
formData.append('ph0t0', s);

axios.post("http://10.0.1.2:8888/uploadphoto", {
        method: "POST",
        headers: {
                'Content-Type': 'multipart/form-data; charset=utf-8; boundary="another cool boundary";'
        },
        body: formData,
}).then((resp) => {
        console.log(resp);
}).catch(err => {
        console.log(err);
});

MultipartForm, Form ๋˜๋Š” PostForm์— ์ผ๋ถ€ ํ‚ค:๊ฐ’ ์Œ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

2018/02/20 18:25:31.740 [W] [photo.go:411] req.MultipartForm: nil
2018/02/20 18:25:31.740 [W] [photo.go:412] req.Form: map[]
2018/02/20 18:25:31.740 [W] [photo.go:413] req.
2018/02/20 18:25:31.740 [W] [photo.go:410] ์š”์ฒญ: &{POST /uploadphoto/dialog/57120e8951c643ab42a8c19f/0000000000000000000000 =utf-8] User-Agent:[okhttp/3.6.0] Accept:[application/json, text/plain, / ] Content-Length:[419] ์—ฐ๊ฒฐ:[Keep-Alive] Accept-Encoding:[gzip] ์ฟ ํ‚ค:[lang=zh-TW; PVsessionID=db9a21d63b2d0ea47b68fa8755bd87e2]] 0xc420e3cb80419 [] ๊ฑฐ์ง“ 10.0.1.2:8888 ์ง€๋„[] ์ง€๋„[]์ง€๋„[] 10.0.1.3:46904 /uploadphoto/dialog/57120e8951c643ab42a8c19f/0000000000000000000000010xc420e3cb40}
2018/02/20 18:25:31.740 [E] [photo.go:425] [UploadPhotos] ์˜ค๋ฅ˜: ์š”์ฒญ ์ฝ˜ํ…์ธ  ์œ ํ˜•์ด multipart/form-data๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๋ฒ„์ „ ์ •๋ณด
์ถ•: 0.16.2
์—‘์Šคํฌ: 25.0.0
๋ฐ˜์‘: 16.2.0
๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ: 0.52.0

์ด ๋ฒ„๊ทธ๋Š” ์ตœ์‹  axios์—์„œ ์—ฌ์ „ํžˆ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์™œ ์ด๊ฒƒ์ด ๋‹ซํ˜”์Šต๋‹ˆ๊นŒ?

๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์˜ˆ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด ๋ฐฑ์—…์„ ๊ณต๊ฐœํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

@ Ernie6711 ์ฝ”๋“œ์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์–‘์‹ ๋ฐ์ดํ„ฐ์— ์ถ”๊ฐ€ํ•˜๊ธฐ ์ „์— ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ axios.post(url[, data[, config]])

๋‹ค์Œ์€ ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

const file ={ uri: localUri, name: filename, type: type};
const formData = new FormData();
formData.append('file', s);

const config = {
        headers: {
                'Content-Type': 'multipart/form-data; charset=utf-8; boundary="another cool boundary";'
        }
};

axios.post("http://10.0.1.2:8888/uploadphoto", formData, config).then((resp) => {
        console.log(resp);
}).catch(err => {
        console.log(err);
});

@emilyemorehouse wireshark ์ถ”์ ์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋กœ๋“œ๋˜์ง€๋งŒ ์ ์ ˆํ•œ ์–‘์‹ ๋ฐ์ดํ„ฐ ์ธ์ฝ”๋”ฉ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ๋Š” ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ - ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ „์†ก๋˜์—ˆ์ง€๋งŒ ์ธ์ฝ”๋”ฉ์ด ์ž˜๋ชป๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

POST /myserver HTTP/1.1
Content-Type: multipart/form-data

_parts=USERX%2Cusername&_parts=FILE1%2C%5Bobject%20Object%5D

React Native ํ™˜๊ฒฝ ์™ธ๋ถ€์— ์žˆ์ง€๋งŒ ์ž‘๋™ํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ธ์ฝ”๋”ฉ๋œ ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ์œ„ํ•œ ๋กœ์ปฌ ํด๋ผ์ด์–ธํŠธ ๋ฐ ์„œ๋ฒ„ ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ๋Š” ๋‚ด๊ฐ€ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†๋Š” ๋ณ€์ˆ˜์™€ ์„œ๋ฒ„์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ ์žฌํ˜„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์—…๋กœ๋“œ์— ์ž˜๋ชป๋œ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์–‘์‹ ๋ฐ์ดํ„ฐ ๊ฐœ์ฒด์— ์ถ”๊ฐ€๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@emilyemorehouse ํŒŒ์ผ ์—…๋กœ๋“œ๋Š” ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋ฉฐ ๊ธฐ๋ณธ ๋ฐ˜์‘์—์„œ๋งŒ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์ž์‹ ์„ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด - ๋‹น์‹ ์˜ ํ…Œ์ŠคํŠธ๋Š” ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ ํ™˜๊ฒฝ ์™ธ๋ถ€์— ์žˆ์—ˆ๊ณ , ๋‚˜๋Š” ๊ฑฐ๊ธฐ์—์„œ ์‹œ์ž‘ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค :)

๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ๊ฐ„๋‹จํ•œ ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ์‹œ๋„ํ•˜๊ณ  wireshark ์ถ”์ ์„ ํ™•์ธํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ์ž‘๋™ํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค...

๋‚˜๋Š” ๊ฐ™์€ ๊ฒƒ์„ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค. Axios๋Š” ๋„ค์ดํ‹ฐ๋ธŒ์— ๋ฐ˜์‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@duongtranpyco ํ”„๋กœ์ ํŠธ์—์„œ

์ถ”์‹  JSON์„ ์ฃผ๋กœ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค. ํ•„์ž์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์–‘์‹์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

const request = async ({url, method = 'GET', params, body, responseType = 'json', headers = {}})=>{
    const escape = (data, encode = encodeURIComponent)=>Object.keys(data||{}).reduce((pairs, key)=>{
        for (let value of [].concat(data[key]))
            pairs.push([`${key}`, `${value}`]);
        return pairs;
    }, []).map(pair=>pair.map(encode).join('=')).join('&');

    if (Object.keys(params||{}).length)
        url += '?'+escape(params);
    if (method=='POST' && typeof body=='object')
    {
        if (body instanceof FormData)
            headers['Content-Type'] = 'multipart/form-data';
        else
        {
            body = escape(body);
            headers['Content-Type'] = 'application/x-www-form-urlencoded';
        }
    }
    let {statusCode, request: req} = await new Promise((resolve, reject)=>{
        let xhr = new XMLHttpRequest();
        xhr.open(method, url, true);
        xhr.withCredentials = true;
        xhr.responseType = {json: 'text'}[responseType]||responseType;
        xhr.onload = ()=>resolve({statusCode: xhr.status, request: xhr});
        xhr.onerror = ()=>reject(new TypeError('Network request failed'));
        xhr.ontimeout = ()=>reject(new TypeError('Network request timed out'));
        for (let key in headers)
            xhr.setRequestHeader(key, headers[key]);
        xhr.send(body||null);
    });
    if (statusCode<200 || statusCode>=400)
        throw new Error(`network request failed with ${statusCode}: ${url}`);
    switch(responseType)
    {
        case 'json':
            return JSON.parse(req.responseText);
        case 'text':
            return req.responseText;
        case 'request':
            return req;
    }
    return req.response;
};

request.get = (url, opt = {})=>request({...opt, url, body: null});
request.post = (url, ...args)=>request({...args[1]||{}, url, method: 'POST', body: args[0]});

์•ˆ๋…•ํ•˜์„ธ์š”, ๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ฌด๋„ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๊นŒ?

๋‘ ๋ฒˆ์งธ @giladno. ๋‹ค๋ฅธ ๋ถ€๋ถ„์„ ์ง„ํ–‰ํ•  ๊ฒƒ์ด๋ฏ€๋กœ ๋Œ€์‹  ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•  ๋•Œ fetch()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด์ „์— ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋ฐ์ดํ„ฐ ๋˜๋Š” ์ธ์ˆ˜๋ฅผ ๋ฌธ์ž์—ดํ™”ํ•˜์ง€ ์•Š์•„๋„ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ํ˜ธ์ถœ์„ ๋ฐ›์•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์ „์†ก๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

@ Ernie6711 ๋ถ„๋ช…ํžˆ ํ—ค๋”๊ฐ€ ์†์ƒ๋˜์–ด ์„œ๋ฒ„๊ฐ€ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜๋ฝํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. fetch()๋กœ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ–ˆ๋Š”๋ฐ ๋ฌธ์ œ ์—†์ด ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ์•ฝ๊ฐ„์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ฌธ์ œ๋Š” ํ—ค๋”๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.
์›น์—์„œ ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

let formData = new FormData()
formData.append('key', true // bool value)

๊ทธ๋Ÿฌ๋‚˜ ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ํ‚ค์˜ ๊ฐ’์€ ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

formData.append('key', 'true')

@giladno๊ฐ€ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ URL์— ๊ฒŒ์‹œํ•  ๋•Œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐ˜์‘์— ๋Œ€ํ•ด ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•˜๋ฉฐ ์‚ฌ๋žŒ๋“ค์ด @emilyemorehouse๋ฅผ ๋ณด๊ณ ํ•œ๋‹ค๋Š” ์˜ค๋ฅ˜๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 14์ผ ์ „์— ์˜ค๋ฅ˜๋ฅผ ๋ณด๊ณ ํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/axios/axios/issues/1618 ํ•˜์ง€๋งŒ ์•„๋ฌด๋„ ์‘๋‹ตํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ readme์— ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ axios๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์„ค๋ช…ํ•˜์‹ญ์‹œ์˜ค. ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์€ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค..!

์—ฌ๋Ÿฌ๋ถ„, ๋ฐฉํ–ฅ์€ ๊ณ ๋ง™๊ฒŒ ์ƒ๊ฐํ•˜์ง€๋งŒ "React Native์—์„œ ํŒŒ์ผ ์—…๋กœ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ"์€ ๊ทธ๋ ‡๊ฒŒ ์‰ฌ์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‚˜๋Š” React Native์—์„œ ์ž์ฃผ ์ผํ•˜์ง€ ์•Š์œผ๋ฉฐ ํ…Œ์ŠคํŠธํ•  ํŒŒ์ผ ์—…๋กœ๋“œ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๋ฐ ์ƒ๋‹นํ•œ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค.

React Native์—์„œ ์ž‘๋™ํ•˜๋Š” ์–‘์‹ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ POST๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

    const formData = new FormData();
    formData.append("data", true);

    const config = {
      headers: {
        "Content-Type": "multipart/form-data; charset=utf-8;"
      }
    };

    axios.post(URL, formData, config).then(
      response => {
        console.log({ response });
      },
      error => {
        console.log({ error });
      }
    );

true ๋Š” ์„œ๋ฒ„๋กœ ๋ณด๋‚ผ ๋•Œ ๋ฌธ์ž์—ดํ™”๋˜๋Š”๋ฐ, ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋ˆ„๊ตฌ๋“ ์ง€ ๋‚ด๊ฐ€ ์‰ฝ๊ฒŒ ์Šคํ•€์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์ œ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋” ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

@corujoraphael ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜์…จ๋‚˜์š”?

์ถ”๊ฐ€ํ•˜๊ธฐ ์ง์ „์— "Image.type='image/png" ์™€ ๊ฐ™์€ ์ด๋ฏธ์ง€ ๊ฐœ์ฒด ๋‚ด๋ถ€์— ์œ ํ˜•์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ฝ˜ํ…์ธ  ์œ ํ˜•์„ "Content-Type":"multipart/form-data" .

        image.type='image/png'
        formData.append("resource", image);
        return axios
          .post('yourBAckendUrl', formData, {
            headers: {
              Authorization: "yourTokenHere",
              "Content-Type": "multipart/form-data"
            }
          })

์ด๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋•๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. multipart/form-data๋ฅผ S3(๋น„๋””์˜ค)์— PUTํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์œ ํ˜• ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด๋„ ๋„์›€์ด ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. multipart/form-data ํ—ค๋”๊ฐ€ PUT ์š”์ฒญ์— ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

      const data = new FormData();
      data.append('video', {
          uri: 'file:///<path_to_video_on_iphone.mov',
          type: 'video/quicktime',
          name: 'video.mov',
      });
      response = yield call(() => {
        return api.put(url, data, {
          headers: {
              'Content-Type': 'multipart/form-data',
          },
          transformRequest: [
            (data, headers) => {
                delete headers.common.Authorization;
                return data;
            }
          ]
        });
      });

์ด ๊ฒฝ์šฐ fetch๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค :D

var data = new FormData();  
data.append('my_photo', {  
  uri: filePath, // your file path string
  name: 'my_photo.jpg',
  type: 'image/jpg'
}

fetch(path, {  
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'multipart/form-data'
  },
  method: 'POST',
  body: data
});

axios ๋ฒ„์ „ 0.18.0 ์—์„œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
axios๋Š” FormData ๋ฐ”๋””๋ฅผ ์ƒ์„ฑํ•  ๋•Œ post, put ๋“ฑ์— ๋ฐ”๋””๊ฐ€ ์—†์œผ๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ Content-Type ํ—ค๋”๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋‚ด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

const sendFormData = images => {
   // images is an array of base64 images (strings)
    const formData = new FormData();
    images.forEach((img, i) => {
        formData.append('file', img);
        formData.append('name', `${type}-${i + 1}`);
    });

    config.headers = {
        .'Content-Type': 'multipart/form-data'
     };

     return axios.post(`http://someurl.com/api/upload-images`, formData, config)
            .then(response => {
               // handle success
            })
            .catch(err => {
                // handle err
     });
}

๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฒ„์ „ 0.55.3
์ด ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๋ณธ๋ฌธ์ด ๋น„์–ด ์žˆ๊ณ  Content-Type ํ—ค๋”๊ฐ€ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๊ณ  ๋””๋ฒ„๊ทธ๋ฅผ ํ™•์ธํ•  ๋•Œ ๋‚ด ๋ชธ์€ ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.

screen shot 2018-10-26 at 11 12 10 am

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ ๋‚ด ์ฝ”๋“œ

        const formData = new FormData();
        formData.append('photo', {
          uri: response.uri.replace('file://', ''),
          mineType: 'image/jpeg',
          fileType: 'image/jpg',
          type: 'image/jpg',
          name: 'test.jpg'
        });

        console.log('form data', formData);

         Axios({
           method: 'post',
           url: 'https://dev-host.luxstay.net/api/rooms/10740/photos',
           data: formData,
           headers: {
             Authorization: token,
             'Content-Type': 'multipart/form-data'
           }
         });

์—…๋ฐ์ดํŠธ : ์•ฑ์ด ๋””๋ฒ„๊ทธ ๋ชจ๋“œ์— ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๋ฅผ ๋„๋ฉด ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

axios์—๋Š” xhr ์–ด๋Œ‘ํ„ฐ์— ์ฝ”๋“œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
if (utils.isFormData(requestData)) { delete requestHeaders['Content-Type']; // Let the browser set it }
๋‚˜๋Š” ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ์ฝ”๋“œ์—์„œ ์„ค์ •ํ•˜๋”๋ผ๋„ ๋‹ค์ค‘ ๋ถ€๋ถ„ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ ์ฝ˜ํ…์ธ  ์œ ํ˜• ํ—ค๋”๋ฅผ ์‚ญ์ œํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ์ค„์„ ์ฃผ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์—์„œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ ์ง€ ํ™•์‹ ์ด ์„œ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

axios ๋ฒ„์ „ 0.18.0 ์—์„œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
axios๋Š” FormData ๋ฐ”๋””๋ฅผ ์ƒ์„ฑํ•  ๋•Œ post, put ๋“ฑ์— ๋ฐ”๋””๊ฐ€ ์—†์œผ๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ Content-Type ํ—ค๋”๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋‚ด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

const sendFormData = images => {
   // images is an array of base64 images (strings)
    const formData = new FormData();
    images.forEach((img, i) => {
        formData.append('file', img);
        formData.append('name', `${type}-${i + 1}`);
    });

    config.headers = {
        .'Content-Type': 'multipart/form-data'
     };

     return axios.post(`http://someurl.com/api/upload-images`, formData, config)
            .then(response => {
               // handle success
            })
            .catch(err => {
                // handle err
     });
}

๋ฆฌ์•กํŠธ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฒ„์ „ 0.55.3
์ด ์˜ˆ์ œ ์ฝ”๋“œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์š”์ฒญ ๋ณธ๋ฌธ์ด ๋น„์–ด ์žˆ๊ณ  Content-Type ํ—ค๋”๊ฐ€ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

screen shot 2018-10-26 at 11 12 10 am

๊ทธ๋Ÿผ ์–ด๋–ค ๋ชจ์Šต์ด์–ด์•ผ ํ• ๊นŒ์š”? ๊ฐœ์ฒด ๊ฐœ์ฒด๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

@tkserver ๊ฐ์ฒด๊ฐ€ ์žˆ๊ณ  toString()ํ•  ๋•Œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const a = {
  name: 'dasdasd'
}
console.log(a.toString());

@tkserver ๊ฐ์ฒด๊ฐ€ ์žˆ๊ณ  toString()ํ•  ๋•Œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const a = {
  name: 'dasdasd'
}
console.log(a.toString());

์•„๋งˆ๋„ ๋‚˜๋Š” ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ—ค๋”๋ฅผ ๋ณผ ๋•Œ ์š”์ฒญ ํŽ˜์ด๋กœ๋“œ์— [๊ฐ์ฒด ๊ฐœ์ฒด]๊ฐ€ ํ‘œ์‹œ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@tkserver ๋””๋ฒ„๊ฑฐ์— ๋„คํŠธ์›Œํฌ ๊ฒ€์‚ฌ๊ฐ€ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉด ๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ์˜ FormData๋ฅผ ์žฌ์ •์˜ํ•˜๊ณ  ๋„คํŠธ์›Œํฌ ๊ฒ€์‚ฌ์—์„œ [๊ฐ์ฒด ๊ฐ์ฒด]์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๋นˆ FormData ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
๋„คํŠธ์›Œํฌ ๊ฒ€์‚ฌ๋ฅผ ๋„๊ณ  ์š”์ฒญ์„ ํ•ด๋ณด์„ธ์š”. ๋„์›€์ด ๋˜๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค.

Aman725, minhphung210 ๋“ฑ ๋ชจ๋‘์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์‹ค์ œ ๊ธฐ๊ธฐ์—์„œ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—…๋กœ๋“œ๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ iOS ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ์™€ ๊ด€๋ จ์ด ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ ์ง€๊ธˆ์€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ์ด์œ ๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋””๋ฒ„๊น…ํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‚ด ์•ฑ์˜ ์ง„์ž…์ ์— ๋‹ค์Œ ์ฝ”๋“œ ์ค„์ด ์žˆ์Šต๋‹ˆ๋‹ค.

GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest;

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋Œ“๊ธ€๋กœ ๋‹ฌ์•˜๊ณ  ์ง€๊ธˆ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

// IMPORTANT: this will cause FormData requests to fail.
// GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest;

๋ฐฉ๊ธˆ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค: https://stackoverflow.com/a/47630754/387912 , ๋„์›€์ด ๋˜๋‚˜์š”?

XMLHttpRequest

์š”์ฒญ์ด ๋‹ค์ž๊ฐ„์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์—…๋กœ๋“œ๋˜๋„๋ก ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ–ˆ๋Š”์ง€ ์•Œ๋ ค์ฃผ์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Error: Network Error
    at createError (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:168963:17)
    at XMLHttpRequest.handleError (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:168871:16)
    at XMLHttpRequest.dispatchEvent (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:28708:27)
    at XMLHttpRequest.setReadyState (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:28461:20)
    at XMLHttpRequest.__didCompleteResponse (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:28288:16)
    at blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:28398:47
    at RCTDeviceEventEmitter.emit (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:3291:37)
    at MessageQueue.__callFunction (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:2588:44)
    at blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:2345:17
    at MessageQueue.__guard (blob:http://localhost:8081/0754d453-361d-48d1-aaa5-9ff1ad808293:2542:13)

์—…๋ฐ์ดํŠธ: ์ง€๊ธˆ ์ž‘๋™ํ•˜๋„๋ก ๊ด€๋ฆฌํ•˜์‹ญ์‹œ์˜ค. ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘:

formData.append('picture', {
          uri: data.uri,
          name: fname,
          type: 'image/' + ext

        });

์‚ฌ๋žŒ๋“ค์ด ์—ฌ์ „ํžˆ ์ด ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ๊ณ  ๊ท€ํ•˜๋Š”
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest;
๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋””๋ฒ„๊ทธํ•˜๊ธฐ ์œ„ํ•œ ์Šค๋‹ˆํŽซ, ์ถ”๊ฐ€ ์‹œ๋„
GLOBAL.FormData = GLOBAL.originalFormData || GLOBAL.FormData
๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€ํ•˜๊ธฐ ์ง์ „์— "Image.type='image/png" ์™€ ๊ฐ™์€ ์ด๋ฏธ์ง€ ๊ฐœ์ฒด ๋‚ด๋ถ€์— ์œ ํ˜•์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ฝ˜ํ…์ธ  ์œ ํ˜•์„ "Content-Type":"multipart/form-data" .

        image.type='image/png'
        formData.append("resource", image);
        return axios
          .post('yourBAckendUrl', formData, {
            headers: {
              Authorization: "yourTokenHere",
              "Content-Type": "multipart/form-data"
            }
          })

์ด๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋•๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋‹น์‹ ์˜ ๋„์›€์„ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! iOS Simunator๋กœ ๋‚ด ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ Android Simunator๋กœ๋Š” ์—…๋กœ๋“œํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€ ์œ ํ˜•์„ 'image/jpeg'๋กœ ์„ค์ •ํ•œ ํ›„ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

const formData = new FormData();
formData.append('file', {
  uri: pictureUri,
  type: 'image/jpeg',
  name: 'profile-picture'
})

์ถ”๊ฐ€ํ•˜๊ธฐ ์ง์ „์— "Image.type='image/png" ์™€ ๊ฐ™์€ ์ด๋ฏธ์ง€ ๊ฐœ์ฒด ๋‚ด๋ถ€์— ์œ ํ˜•์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ฝ˜ํ…์ธ  ์œ ํ˜•์„ "Content-Type":"multipart/form-data" .

        image.type='image/png'
        formData.append("resource", image);
        return axios
          .post('yourBAckendUrl', formData, {
            headers: {
              Authorization: "yourTokenHere",
              "Content-Type": "multipart/form-data"
            }
          })

์ด๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋•๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋‹น์‹ ์˜ ๋„์›€์„ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! iOS Simunator๋กœ ๋‚ด ์‚ฌ์ง„์„ ์—…๋กœ๋“œํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ Android Simunator๋กœ๋Š” ์—…๋กœ๋“œํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€ ์œ ํ˜•์„ 'image/jpeg'๋กœ ์„ค์ •ํ•œ ํ›„ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

const formData = new FormData();
formData.append('file', {
  uri: pictureUri,
  type: 'image/jpeg',
  name: 'profile-picture'
})

์ด๊ฒƒ์ด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์ „์†ก๋  ์ฝ˜ํ…์ธ  ์œ ํ˜•์„ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ multipart/form-data . ์ง€๊ธˆ ์ด๊ฒƒ์„ ์ฝ๋Š” ๊ฒƒ์ด ๋‹น์—ฐํ•˜๊ฒŒ ๋“ค๋ฆฌ์ง€๋งŒ ๋ฏธ๋””์–ด๊ฐ€ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ๋ฐ ์ข‹์€ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค.

    data.append("image", {
      name: "some_name", // also, won't work without this. A name is required
      height: image.height,
      width: image.width,
      type: "multipart/form-data", // <-- this part here
      uri:
        Platform.OS === "android" ? image.uri : image.uri.replace("file:/", "")
    });

์•ˆ๋…•ํ•˜์„ธ์š”, Vue.Js์—์„œ Axios ์—…๋กœ๋“œ ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฌ๋“ ์ง€ ๋ฌธ์ œ๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ  ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

HTML์—์„œ
<input type="file" id="file" ref="file" multiple @change="assignFiles"/>

Js์—์„œ

` assignFiles(e){

      let uploadedFiles = this.$refs.file.files;
      for( var i = 0; i < uploadedFiles.length; i++ ) { 
        this.form.AttachmentDocs.push(uploadedFiles[i]);           
      }
      console.log(this.form.AttachmentDocs);
 },`

๋”ฐ๋ผ์„œ ๊ฒŒ์‹œ๋ฌผ์„ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๋™์•ˆ ์–‘์‹ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

`procedSave(e) {

      e.preventDefault();
      this.$v.$touch();
      if(this.$v.$invalid) {
        return;
      }
    this.showLoading(this.loaderId,true);
      this.postDatas.append('form',JSON.stringify(this.form));
      for( var i = 0; i < this.form.AttachmentDocs.length; i++ ){ 
        let attachment = this.form.AttachmentDocs[i];
        this.postDatas.append('files['+i+']',attachment,attachment.name);           
      }

}`

๊ทธ๋ž˜์„œ ๊ฒŒ์‹œ๋ฌผ์—์„œ ์ฝ˜์†” ์ฐฝ ํ—ค๋”๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

ํŒŒ์ผ[0]: (๋ฐ”์ด๋„ˆ๋ฆฌ)
ํŒŒ์ผ[1]: (๋ฐ”์ด๋„ˆ๋ฆฌ)
ํŒŒ์ผ[2]: (๋ฐ”์ด๋„ˆ๋ฆฌ)
ํŒŒ์ผ[3]: (๋ฐ”์ด๋„ˆ๋ฆฌ)

๋‚ด ์„œ๋ฒ„ ์ธก์—์„œ ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์™€ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

this.postDatas.append('files['+i+']',attachment,attachment.name);  

files['+' + i + '+'] ์‹œ๋„

๊ฐ€์ ธ์˜ค๊ธฐ API์™€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. req.body๋Š” ๋…ธ๋“œ js์—์„œ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค. 'express-formidable'์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. https://www.npmjs.com/package/express-formidable

์™€ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

this.postDatas.append('files['+i+']',attachment,attachment.name);  

files['+' + i + '+'] ์‹œ๋„

Sry + ๋Š” ์—ฐ๊ฒฐ์„ ๋‚˜ํƒ€๋‚ด๊ณ  wat ๋Š” ๋ฌธ์ž์—ด '+' ์˜ ์‚ฌ์šฉ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” ํŒŒ์ผ[+0+]์ด ๋ฉ๋‹ˆ๋‹ค.

๊ฐ€์ ธ์˜ค๊ธฐ API์™€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. req.body๋Š” ๋…ธ๋“œ js์—์„œ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค. 'express-formidable'์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. https://www.npmjs.com/package/express-formidable

app.use(express.json({ extended: false })); ๋ฅผ ํฌํ•จํ–ˆ์Šต๋‹ˆ๊นŒ?

์™€ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

this.postDatas.append('files['+i+']',attachment,attachment.name);  

files['+' + i + '+'] ์‹œ๋„

Sry + ๋Š” ์—ฐ๊ฒฐ์„ ๋‚˜ํƒ€๋‚ด๊ณ  wat ๋Š” ๋ฌธ์ž์—ด '+' ์˜ ์‚ฌ์šฉ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋Š” ํŒŒ์ผ[+0+]์ด ๋ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ ์ฝ”๋“œ๋Š” ํ•ญ์ƒ for ๋ฃจํ”„์—์„œ files[+i+] ๋ฉ๋‹ˆ๋‹ค. ์ ˆ๋Œ€ files[+0+], files[+1+], files[+2+], etc ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ files[+0+] ๋Š” ์ ˆ๋Œ€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋ฌด์—‡์„ํ•˜๋ ค๊ณ ํ•˜๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. files[0], files[1], files[2]... ํ•˜์‹ญ๋‹ˆ๊นŒ? ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ•œ๋‹ค๋ฉด files['+0+'] ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋ฌด์—‡์„ ์„ฑ์ทจํ•˜๋ ค๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ€์ ธ์˜ค๊ธฐ API์™€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. req.body๋Š” ๋…ธ๋“œ js์—์„œ ๋น„์–ด ์žˆ์Šต๋‹ˆ๋‹ค. 'express-formidable'์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. https://www.npmjs.com/package/express-formidable

app.use(express.json({ extended: false })); ๋ฅผ ํฌํ•จํ–ˆ์Šต๋‹ˆ๊นŒ?
์•„๋‹ˆ์š”. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ•๋ ฅํ•œ ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—…๋กœ๋“œ๋œ ์‚ฌ์ง„์€ ํ•„๋“œ๋ฅผ ์š”์ฒญํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ ํŒŒ์ผ์— ์•„๋ฌด๊ฒƒ๋„ ์—†์Šต๋‹ˆ๋‹ค. ์™œ ์ด๋Ÿฐ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@duongtranpyco ํ”„๋กœ์ ํŠธ์—์„œ

์ถ”์‹  JSON์„ ์ฃผ๋กœ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์‹ญ์‹œ์˜ค. ํ•„์ž์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์–‘์‹์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

const request = async ({url, method = 'GET', params, body, responseType = 'json', headers = {}})=>{
    const escape = (data, encode = encodeURIComponent)=>Object.keys(data||{}).reduce((pairs, key)=>{
        for (let value of [].concat(data[key]))
            pairs.push([`${key}`, `${value}`]);
        return pairs;
    }, []).map(pair=>pair.map(encode).join('=')).join('&');

    if (Object.keys(params||{}).length)
        url += '?'+escape(params);
    if (method=='POST' && typeof body=='object')
    {
        if (body instanceof FormData)
            headers['Content-Type'] = 'multipart/form-data';
        else
        {
            body = escape(body);
            headers['Content-Type'] = 'application/x-www-form-urlencoded';
        }
    }
    let {statusCode, request: req} = await new Promise((resolve, reject)=>{
        let xhr = new XMLHttpRequest();
        xhr.open(method, url, true);
        xhr.withCredentials = true;
        xhr.responseType = {json: 'text'}[responseType]||responseType;
        xhr.onload = ()=>resolve({statusCode: xhr.status, request: xhr});
        xhr.onerror = ()=>reject(new TypeError('Network request failed'));
        xhr.ontimeout = ()=>reject(new TypeError('Network request timed out'));
        for (let key in headers)
            xhr.setRequestHeader(key, headers[key]);
        xhr.send(body||null);
    });
    if (statusCode<200 || statusCode>=400)
        throw new Error(`network request failed with ${statusCode}: ${url}`);
    switch(responseType)
    {
        case 'json':
            return JSON.parse(req.responseText);
        case 'text':
            return req.responseText;
        case 'request':
            return req;
    }
    return req.response;
};

request.get = (url, opt = {})=>request({...opt, url, body: null});
request.post = (url, ...args)=>request({...args[1]||{}, url, method: 'POST', body: args[0]});

๋‚ด ํ”„๋กœ์ ํŠธ์—์„œ ์ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•œ ๊ฐ€์ง€ ์งˆ๋ฌธ์€ ์ด ์ค„์ด ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ?
([].concat(data[key])์˜ ๊ฐ’์„ ๋ณด์ž)? ๊ฐ„๋‹จํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ๋Š”๋ฐ,
pair.push([ ${key} , ${data[key]} ]);

์‚ฌ๋žŒ๋“ค์ด ์—ฌ์ „ํžˆ ์ด ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ๊ณ  ๊ท€ํ•˜๋Š”
GLOBAL.XMLHttpRequest = GLOBAL.originalXMLHttpRequest || GLOBAL.XMLHttpRequest;
๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋””๋ฒ„๊ทธํ•˜๊ธฐ ์œ„ํ•œ ์Šค๋‹ˆํŽซ, ์ถ”๊ฐ€ ์‹œ๋„
GLOBAL.FormData = GLOBAL.originalFormData || GLOBAL.FormData
๊ทธ๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ณณ์€?

๋‚˜๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค. Android์˜ ํŒŒ์ผ ๊ฒฝ๋กœ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
const ๊ฒฝ๋กœ = utils.isAndroid() ?
๊ทธ๋ฆฌ๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ตฌํ˜„ํ•˜๋ฉด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

    const formData = new FormData();
    const path = utils.isAndroid() ? `file://${filePath}` : filePath;
    formData.append('Voice', {
      uri: path,
      name: 'test',
      type: 'audio/wav',
    });

    formData.append('Content-Type', 'audio/wav');
     const headers =  {
        'Content-Type': 'multipart/form-data',
      };
    return this._sendRequest(url, 'POST', formData, headers);
 data.append('file', {
    uri: newData.image.path,
    type: 'image/jpeg',
    name: 'teste'

name:'teste.jpeg' ์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํŒŒ์ผ์— ํ˜•์‹์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
'example.jpeg'๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฉฐ์น  ๋™์•ˆ axios๋กœ ๋น„๋””์˜ค๋ฅผ ์—…๋กœ๋“œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋‹ค๊ฐ€ ๊ทธ๋ƒฅ ํฌ๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. RNFetchBlob์€ ํŠนํžˆ Android์—์„œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋Š” ๋ฐ ๋” ๋‚˜์€ ์˜ต์…˜์ž…๋‹ˆ๋‹ค. ์ด ์„น์…˜์€ ๊ตฌํ˜„ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

rn-ํŽ˜์น˜-๋ธ”๋กญ

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰