Axios: POST ์š”์ฒญ์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋…ธ๋“œ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2017๋…„ 07์›” 20์ผ  ยท  26์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: axios/axios

#318 ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋…ธ๋“œ์—์„œ axios๋กœ ๊ฒŒ์‹œ๋ฌผ ์š”์ฒญ์„ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ๋™์ผํ•œ ์ฝ”๋“œ๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const fdata = new FormData();
fdata.append('user', u);
fdata.append('hostnames', n.join(' '));
const host = localStorage.getItem('host');
const port = localStorage.getItem('port');
axios({
  url: `http://${host}:${port}/hosts/remove`,
  method: 'post',
  data: fdata
}).then(response => {
  if (response.status === 200) {
    console.log(response.data);
    console.log('Removed host successfully');
  }
  return null;
}).catch(er => console.log(er));

๋ถˆ์•ˆํ•˜๋ฉด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

unirest.post(`http://${host}:${port}/hosts/remove`)
.headers({ 'Content-Type': 'multipart/form-data' })
.field('user', u)
.field('hostnames', h.join(' '))
.end(response => {
  console.log(response.body);
});
  • ์•ก์‹œ์˜ค์Šค ๋ฒ„์ „:
  • ํ™˜๊ฒฝ: ๋…ธ๋“œ v8.0.0, Windows 8.1

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

์ด๊ฒƒ์€ #789์˜ ์ค‘๋ณต์œผ๋กœ ๊ฐ„์ฃผ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

nodejs์—์„œ Axios์™€ ํ•จ๊ป˜ form-data ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ FormData ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ์„ฑํ•˜๋Š” ํ—ค๋”๋ฅผ Axios์— ์ˆ˜๋™์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios.post('http://example.org/endpoint', form, {
  headers: form.getHeaders(),
}).then(result => {
  // Handle resultโ€ฆ
  console.log(result.data);
});

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

์ด๊ฒƒ์€ #789์˜ ์ค‘๋ณต์œผ๋กœ ๊ฐ„์ฃผ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

nodejs์—์„œ Axios์™€ ํ•จ๊ป˜ form-data ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ FormData ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ์„ฑํ•˜๋Š” ํ—ค๋”๋ฅผ Axios์— ์ˆ˜๋™์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios.post('http://example.org/endpoint', form, {
  headers: form.getHeaders(),
}).then(result => {
  // Handle resultโ€ฆ
  console.log(result.data);
});

์˜ˆ, form-data ํŒจํ‚ค์ง€๋กœ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  JSON์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋„๋ก ์„œ๋ฒ„ ์ธก API๋ฅผ ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ nodejs ์•ฑ์—์„œ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ์ž‘์—…์„ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@ar412 https://github.com/mzabriskie/axios/issues/1006#issuecomment -320165427์—์„œ ์˜ˆ์ œ๋ฅผ ์ œ๊ณตํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. ์งˆ๋ฌธํ•˜์‹  ๋‚ด์šฉ์„ ๋ช…ํ™•ํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@binki axios๊ฐ€ ์ผ๋ถ€ ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ restapi์—์„œ ๊ฒŒ์‹œ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ ๋‚˜๋จธ์ง€ API(์ต์Šคํ”„๋ ˆ์Šค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด๋ถ€์— ์žˆ์Œ)์—์„œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฐฉ๋ฒ•.

๋‹น์‹ ์€ ์ด๊ฒƒ์„ ์‹œ๋„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค https://expressjs.com/en/4x/api.html#req @ar412

@ar412 Express์—์„œ ๋ฉ€ํ‹ฐํŒŒํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜๋ ค๋ฉด body-parser ์˜ ๋ฌธ์„œ์—์„œ ๊ถŒ์žฅํ•˜๋Š” ๋Œ€๋กœ busboy ์™€ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ Express์—์„œ ์—…๋กœ๋“œ๋œ ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋ ค๋ฉด Axios์™€ ์ „ํ˜€ ๊ด€๋ จ์ด ์—†์œผ๋ฏ€๋กœ ์ด ์Šค๋ ˆ๋“œ๋ฅผ ํ•˜์ด์žฌํ‚นํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ๊ณณ์—์„œ ๋ฌผ์–ด๋ณด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค ;-). ์˜ˆ๋ฅผ ๋“ค์–ด SO ์— ๋Œ€ํ•œ ํ•˜์„ธ์š” .

์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋ฐœ์ƒ: form.getHeaders()๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

@binki
์ด๋ด! fs.readFile(path)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€์ˆ˜์— ์ €์žฅ๋œ ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ POSTํ•˜๋ ค๋Š” hapi.js ์„œ๋ฒ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
FormData()๋กœ ๋ณด๋‚ด๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

fs.readFile(__dirname+'/../static/lisa_server.jpg', (error, imageData) => {
          var form = new FormData()

            form.append('file', imageData,  {
            filename: 'unicycle.jpg', // ... or:
            filepath: '/../static/lisa_server.jpg',
            contentType: 'image/jpg',
            knownLength: 19806
          })

๊ทธ๋Ÿฐ ๋‹ค์Œ ์š”์ฒญ์˜ ๋ณธ๋ฌธ์œผ๋กœ ์–‘์‹์„ ๋ณด๋‚ด๊ณ  options['Content-Type'] = 'multipart/form-data'๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

๋„์™€์ฃผ์‹œ๊ฒ ์–ด์š”?
๋งค์šฐ ๊ฐ์‚ฌ!

@bstolarz ๋‹น์‹ ์ดํ•˜๊ณ ์žˆ๋Š” Buffer ์ „๋‹ฌํ•˜๋ฉด knownLength ์ „๋‹ฌํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์„ ์ฝ๋Š” ๊ฒฝ์šฐ( form-data ์˜ README ์˜ˆ์ œ ์—์„œ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ filename ๋˜๋Š” filepath ์ค‘ ํ•˜๋‚˜๋งŒ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‘˜ ๋‹ค ์ œ๊ณตํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ผ ์ˆ˜ ์žˆ๋Š” ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. filename ๋˜๋Š” filepath
  2. contentType (์„œ๋ฒ„์— ํŠน์ • Content-Type ๊ฐ’์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Œ).

๋‚ด๊ฐ€ ์˜ˆ์ƒํ•˜๋Š” ๋ฐ”๋Š” 19806 ๊ฐ’์ด form-data ์˜ ์˜ˆ์ œ์—์„œ ๋ณต์‚ฌํ•œ ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ณด๋‚ด๋Š” ์ด๋ฏธ์ง€์˜ ํฌ๊ธฐ๊ฐ€ 19806 ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ž์‹ ์˜ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ๊ณ„์‚ฐ๋œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์˜ ๋ฌธ์„œ ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. ์ด๋กœ ์ธํ•ด form-data ์—์„œ ์ž์ฒด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ HTTP ์š”์ฒญ์— ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. axios.post() ๋ฐ˜ํ™˜๋œ Promise ์ด ๊ฑฐ๋ถ€๋˜๊ฑฐ๋‚˜ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๊นŒ? axios ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋˜๋ฉด ์˜ค๋ฅ˜ ๊ฐœ์ฒด์— result ํ‚ค๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์žˆ์œผ๋ฉด err.result.status ๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. 404 ๋˜๋Š” 403์ด ์•„๋‹Œ 4xx ๊ฐ’์ธ ๊ฒฝ์šฐ ์ด๋Š” ์„œ๋ฒ„๊ฐ€ ์ž˜๋ชป๋œ ์•Œ๋ ค์ง„ ํฌ๊ธฐ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ž˜๋ชป๋œ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•˜๊ณ  ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

@binki
๋‹ต๋ณ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์–ธ๊ธ‰ ํ•œ ๊ฒƒ์„ ์ˆ˜์ • ํ–ˆ์œผ๋ฏ€๋กœ ์ด์ œ ๋‚ด ์ฝ”๋“œ๋Š”

fs.readFile(__dirname+'/../static/lisa_server.jpg', (error, imageData) => {
          var form = new FormData()

          form.append('file', imageData, {
               filepath: __dirname+'/../static/lisa_server.jpg',
               contentType: 'image/jpg'

          })

๊ทธ๋Ÿฌ๋‚˜ ์„œ๋ฒ„๋Š” 411 "๊ธธ์ด๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค"๋ฅผ ๋˜์กŒ์Šต๋‹ˆ๋‹ค(FormData์—์„œ ์™„์ „ํžˆ ์ง€์›๋˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š” fs.createReadStream๋„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋™์ผํ•œ ๊ธธ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•จ).

@binki
๊ฐ€์žฅ ๋‚ฎ์€ ๋ ˆ์ด์–ด์—์„œ ํ—ค๋” ๋‚ด์šฉ ๊ธธ์ด๋ฅผ ์„ค์ •ํ–ˆ๋Š”๋ฐ ๋” ์ด์ƒ ํ•ด๋‹น ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด์ œ ์„œ๋ฒ„์—์„œ 411์„ ๋ฐ›์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ๋•Œ 400-"ํŒŒ์ผ์ด ์ œ๊ณต๋˜์ง€ ์•Š์Œ" ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์š”์ฒญ์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค

์‹œ์ž‘ ์š”์ฒญ

{ adapter: [Function: httpAdapter],
  transformRequest: { '0': [Function: transformRequest] },
  transformResponse: { '0': [Function: transformResponse] },
  timeout: 5000,
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  maxContentLength: -1,
  validateStatus: [Function: validateStatus],
  headers:
   { common: { Accept: 'application/json, text/plain, */*' },
     delete: {},
     get: {},
     head: {},
     post: { 'Content-Type': 'application/json' },
     put: { 'Content-Type': 'application/json' },
     patch: { 'Content-Type': 'application/json' },
     'User-Agent': 'trojan server 1.0',
     'X-Origin-Panamera': 'Staging',
     'Content-Length': 25247 },
  baseURL: 'https://letgoar-a.akamaihd.net/api/v1',
  method: 'post',
  url: 'https://<baseDomain>/api/v1/images',
  data:
   FormData {
     _overheadLength: 218,
     _valueLength: 25247,
     _valuesToMeasure: [],
     writable: false,
     readable: true,
     dataSize: 0,
     maxDataSize: 2097152,
     pauseStreams: true,
     _released: false,
     _streams:
      [ '----------------------------677738213014296377492349\r\nContent-Disposition: form-data; name="file"; filename="/Users/brenda/repos/qreator2/qreator/trojan-server/src/static/lisa_server.jpg"\r\nContent-Type: image/jpg\r\n\r\n',
        <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 01 00 48 00 48 00 00 ff e2 11 2c 49 43 43 5f 50 52 4f 46 49 4c 45 00 01 01 00 00 11 1c 61 70 70 6c 02 00 00 00 ... >,
        [Function: bound ] ],
     _currentStream: null,
     _boundary: '--------------------------677738213014296377492349' },
  'Content-Type': 'multipart/form-data' }

์ด๊ฒƒ์„ ํ™•์ธํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋ณด๊ธฐ์— ์ด๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ธ ์š”๊ตฌ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๊นŒ?

๋ฏธ๋ฆฌ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค

@bstolarz ๊ท€ํ•˜์˜ ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์„ ์„ ๋‹คํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ดํ•˜๋Š” ์ผ์„ ๋ชจ๋ฐฉํ•˜๋ ค๊ณ ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Content-Length ์ˆ˜๋™ ์„ค์ •์„ ์˜๋„์ ์œผ๋กœ ์ƒ๋žตํ–ˆ์Šต๋‹ˆ๋‹ค. Content-Length ์„ค์ •ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์ด ๊ท€ํ•˜์˜ ๋ฌธ์ œ์™€ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. form-data ๊ฐ€ ์•Œ์•„์„œ ๊ณ„์‚ฐํ•˜๋„๋ก ํ•˜์„ธ์š”. ๊ทธ๋ž˜์„œ form.getHeaders() ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ŠคํŠธ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค: https://gist.github.com/binki/10ac3e91851b524546f8279733cdadad . ์•„๋งˆ๋„ ๋‚ด ์˜ˆ์™€ ์ผ์น˜ํ•˜๋„๋ก axios.post() ๋˜๋Š” axios() ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ž‘๋™ํ• ๊นŒ์š”?

์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์ž์ฒด ์Šคํฌ๋ฆฝํŠธ๋กœ ์ด๋™ํ•˜๊ณ  ๊ฑฐ๊ธฐ์—์„œ ์žฌํ˜„ํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์œผ๋ฉด axios() ๋˜๋Š” axios.post() ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ํฌํ•จํ•˜์—ฌ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ์š”์ ์œผ๋กœ ๊ฒŒ์‹œํ•˜๊ณ  ์—ฌ๊ธฐ์— ๋งํฌํ•˜๊ณ  ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์กฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์—ฌ์ „ํžˆ ์ „ํ˜€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค ...

@rodrigogs ๋„์›€์ด ํ•„์š”ํ•˜๋ฉด ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค ;-).

Axios์— ๋Œ€ํ•œ ์ด ์œ ์šฉํ•œ ์—ฐ๊ตฌ๋ฅผ ๋”ฐ๋ž๊ณ  ์ตœ์ข… ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค( ๋งํฌ ).

๋ณต์‚ฌ/๋ถ™์—ฌ๋„ฃ๊ธฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import fs from 'fs';
import FormData from 'form-data';
import axios from 'axios';

let data = fs.createReadStream(__dirname + '/test.jpg');
let form = new FormData();

form.append('type','image');
form.append('media',data,'test.jpg');

function getHeaders(form) {
    return Promise((resolve, reject) => {
        form.getLength((err, length) => {
            if(err) { reject(err); }
            let headers = Object.assign({'Content-Length': length}, form.getHeaders());
            resolve(headers);
         });
    });
}

getHeaders(form)
.then((headers) => {
    return axios.post(url, form, {headers:headers})
})
.then((response)=>{
    console.log(response.data)
})
.catch(e=>{console.log(e)})

@westofpluto , @binki , ์–ด๋–ค ์ƒ๊ฐ์ด ์žˆ์Šต๋‹ˆ๊นŒ?
์˜ค๋ฅ˜
form.getHeaders๋Š” ํ•จ์ˆ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

@smplyjr ๋” ๋งŽ์€ ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•˜๊ณ  form ๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด ์šฐ๋ฆฌ๋Š” ๋‹น์‹ ์ด ๋ฌด์—‡์„ ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ณ  ๋‹น์‹ ์„ ๋„์šธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

nodejs ์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด lib๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

const querystring = require('querystring')
axios
  .post(URL, querystring.stringify(data))
  .then((response) => ...)
  .catch((error) => ...)

@heldrida๊ฐ€ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์ด axios๊ฐ€ https://www.npmjs.com/package/axios#nodejs ์—์„œ๋„ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ• form-data ํŒจํ‚ค์ง€์—๋Š” ์—ฌ๊ธฐ์— ๋ชจ๋“  ์ข…๋ฅ˜์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉฐ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ๋จธ๋ฆฌ๋ฅผ ๋ฝ‘๊ฒŒ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@heldrida @ashok-sc querystring ๋˜๋Š” qs ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? axios๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ AWS Lambda์—์„œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๋ถ„๋ช…ํžˆ ๊ฑฐ๊ธฐ์—์„œ File ๊ฐ์ฒด์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@bstolarz ๊ท€ํ•˜์˜ ๋ฌธ์ œ๋ฅผ ์žฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ตœ์„ ์„ ๋‹คํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ดํ•˜๋Š” ์ผ์„ ๋ชจ๋ฐฉํ•˜๋ ค๊ณ ์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Content-Length ์ˆ˜๋™ ์„ค์ •์„ ์˜๋„์ ์œผ๋กœ ์ƒ๋žตํ–ˆ์Šต๋‹ˆ๋‹ค. Content-Length ์„ค์ •ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์ด ๊ท€ํ•˜์˜ ๋ฌธ์ œ์™€ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. form-data ๊ฐ€ ์•Œ์•„์„œ ๊ณ„์‚ฐํ•˜๋„๋ก ํ•˜์„ธ์š”. ๊ทธ๋ž˜์„œ form.getHeaders() ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ŠคํŠธ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค: https://gist.github.com/binki/10ac3e91851b524546f8279733cdadad . ์•„๋งˆ๋„ ๋‚ด ์˜ˆ์™€ ์ผ์น˜ํ•˜๋„๋ก axios.post() ๋˜๋Š” axios() ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ž‘๋™ํ• ๊นŒ์š”?

์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ฝ”๋“œ๋ฅผ ์ž์ฒด ์Šคํฌ๋ฆฝํŠธ๋กœ ์ด๋™ํ•˜๊ณ  ๊ฑฐ๊ธฐ์—์„œ ์žฌํ˜„ํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์œผ๋ฉด axios() ๋˜๋Š” axios.post() ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ํฌํ•จํ•˜์—ฌ ์ „์ฒด ์ฝ”๋“œ๋ฅผ ์š”์ ์œผ๋กœ ๊ฒŒ์‹œํ•˜๊ณ  ์—ฌ๊ธฐ์— ๋งํฌํ•˜๊ณ  ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์กฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ณ ๋งˆ์›Œ์š”. Content-Length๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‚ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ FormData์™€ ํ•จ๊ป˜ axios backend-2-backend ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const options = { method: 'POST', url: myUrl, data: justJsonBody, transformRequest: [function (data, headers) { const formData = convertToFormData(data); // returrns ForrmData from form-data headers['Content-Type'] = formData.getHeaders()['content-type']; headers['Content-Length'] = formData._overheadLength; return formData; }] };

์ด๊ฒƒ์€ #789์˜ ์ค‘๋ณต์œผ๋กœ ๊ฐ„์ฃผ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

nodejs์—์„œ Axios์™€ ํ•จ๊ป˜ form-data ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ FormData ๊ฐ™์€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ƒ์„ฑํ•˜๋Š” ํ—ค๋”๋ฅผ Axios์— ์ˆ˜๋™์œผ๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด:

const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios.post('http://example.org/endpoint', form, {
  headers: form.getHeaders(),
}).then(result => {
  // Handle resultโ€ฆ
  console.log(result.data);
});

์—ฌ๊ธฐ ๋˜ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ํ”„๋ก์‹œ ์—์ด์ „ํŠธ๋ฅผ ๋ฐ ๊ธฐํƒ€ ๊ตฌ์„ฑ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const axios = require('axios');
const FormData = require('form-data');
const ProxyAgent = require('proxy-agent');

const form = new FormData();
// Second argument  can take Buffer or Stream (lazily read during the request) too.
// Third argument is filename if you want to simulate a file upload. Otherwise omit.
form.append('field', 'a,b,c', 'blah.csv');
axios({
  method: 'POST',
  url: 'http://example.org/endpoint',
  data: form,
  agent: new ProxyAgent("https://username:[email protected]:8080"),
  headers: bodyFormData.getHeaders()
}).then(result => {
  // Handle resultโ€ฆ
  console.log(result.data);
});

์ด๊ฒƒ์€ ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

// ES6
import axios from 'axios';
import FormData from 'form-data';
import fs from 'fs';

FormData.prototype.getHeadersWithContentLength = function getHeadersWithContentLength() {
  return new Promise((resolve, reject) => {
    this.getLength((err, length) =>
      err ? reject(err) : resolve({ ...this.getHeaders(), 'Content-Length': length })
    )
  })
}

const payload = new FormData();
const form = new formidable.IncomingForm();

form.parse(req, (err, fields, { file }) => {
  if (err) return;

  payload.append("file", fs.createReadStream(file.path), {
    filename: file.name,
    contentType: file.type
  });

  payload.getHeadersWithContentLength().then(headers => {
    api
      .post(endpoint, payload, { headers })
      .then(({ data }) => data)
      .then(data => res.json({ data }));
  });
});

์ด ๊ฒŒ์‹œ๋ฌผ์˜ ๋ชจ๋“  ๊ธฐ์—ฌ์ž์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. Axios๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด form-data ์–‘์‹์„ ๊ฒŒ์‹œํ•˜๋Š” ๋ฐ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋‚ธ ํ›„ ์ด๋ฅผ Amazon ๋ฒ„ํ‚ท์— ๊ฒŒ์‹œํ•˜๋Š” ๋ฐฑ์—”๋“œ์— ์†”๋ฃจ์…˜์€ ์ˆ˜๋™์œผ๋กœ content-length ....๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.

๋‚ด ์ฝ”๋“œ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์—๊ฒŒ๋Š” ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋‹ค์Œ ์ค„์— ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. :)

const axios = require('axios');
const FormData = require('form-data');

// Where buffer is a file
formData.append('file', buffer);

// Added a promise version like seen in earlier comments to get this
const contentLength = await formData.getLength();

await axios(`<ENDPOINT>`, {
    method: 'POST',
    baseURL: <BASE_URL>,
    params: {
        fileName: '<FILE_NAME>.png'
    },
    headers: {
        authorization: `Bearer <TOKEN>`,
        ...formData.getHeaders(),
        'content-length': contentLength
    },
    data: formData
});

Axios๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‚ด form-data ์–‘์‹์„ ๊ฒŒ์‹œํ•˜๋Š” ๋ฐ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋‚ธ ํ›„ ์ด๋ฅผ Amazon ๋ฒ„ํ‚ท์— ๊ฒŒ์‹œํ•˜๋Š” ๋ฐฑ์—”๋“œ์— ์†”๋ฃจ์…˜์€ ์ˆ˜๋™์œผ๋กœ content-length ....๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.

์˜ˆ. ๋‚˜์™€ ๋‚ด ๋™๋ฃŒ๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์‘๋‹ตํ•˜๋Š” ๋ฐฑ์—”๋“œ์— ํŒŒ์ผ์„ POSTํ•˜๋ ค๊ณ  ์‹œ๋„ํ•  ๋•Œ ๋ช‡ ์‹œ๊ฐ„์„ ๋ณด๋ƒˆ์ง€๋งŒ ์š”์ฒญ์„ ์ถ”์ ํ•˜๊ณ  ๋‚ด์šฉ์„ ๋ณผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถ„๋ช…ํžˆ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ๋ˆ„๋ฝ๋œ ์ฝ˜ํ…์ธ  ๊ธธ์ด ํ—ค๋”์˜€์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ FormData์— ๋ฒ„ํผ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ formData.getLengthSync() ๋ฅผ ํ˜ธ์ถœํ•ด๋„ ๊ดœ์ฐฎ์ง€๋งŒ ์ŠคํŠธ๋ฆผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ ๋จผ์ € ํŒŒ์ผ์„ fs.statSync(filePath).size ๋˜๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด ์ŠคํŠธ๋ฆผ์ด ์š”์ฒญ์ด๋‚˜ ์†Œ์ผ“ ๋“ฑ์—์„œ ์˜ค๋Š” ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ „์ฒด ํฌ๊ธฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค(์—…์ŠคํŠธ๋ฆผ์˜ ์ฝ˜ํ…์ธ  ๊ธธ์ด ํ—ค๋”์—์„œ). ์ŠคํŠธ๋ฆผ์ด ๋Œ€์‹  ๋””์Šคํฌ์—์„œ ์˜ค๋Š” ๊ฒฝ์šฐ fs.statSync(filePath).size ๋Š” ํฌ๊ธฐ๋ฅผ ๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ์ œ๊ณตํ•˜๋ฏ€๋กœ FormData์— ์ถ”๊ฐ€ํ•  ๋•Œ knownLength์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

formData.append("file", fs.createReadStream(filePath), { filename: 'whatever.pdf', knownLength: fs.statSync(filePath).size });

๋ฌผ๋ก  ๋ชจ๋“  Sync ๋ฉ”์„œ๋“œ๋Š” async ๋ฉ”์„œ๋“œ์™€ await ํ‚ค์›Œ๋“œ๋กœ ์ „ํ™˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// Added a promise version like seen in earlier comments to get this
const contentLength = formData.getLength();

์‹ค์ œ๋กœ formData ์ „์— await ๋ฅผ ์žŠ์–ด ๋ฒ„๋ฆฐ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค ...

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