Request: 파일 μ—…λ‘œλ“œλŠ” ν‘œμ€€ 읽기 μŠ€νŠΈλ¦Όμ—μ„œλ§Œ μž‘λ™ν•©λ‹ˆλ‹€.

에 λ§Œλ“  2016λ…„ 12μ›” 28일  Β·  26μ½”λ©˜νŠΈ  Β·  좜처: request/request

TAR μ•„μΉ΄μ΄λΈŒ 내뢀에 μžˆλŠ” 파일(λ©€ν‹°νŒŒνŠΈ POST μš”μ²­ μ‚¬μš©)을 μ—…λ‘œλ“œν•˜λ €κ³  ν–ˆμŠ΅λ‹ˆλ‹€( tar-stream 라이브러리λ₯Ό μ‚¬μš©ν•˜μ—¬ TAR μ•„μΉ΄μ΄λΈŒ λ‚΄λΆ€μ˜ νŠΉμ • 파일둜 μŠ€νŠΈλ¦Όμ„ κ°€μ Έμ˜΄). κ·ΈλŸ¬λ‚˜ 항상 ECONNRESET 였λ₯˜λ‘œ μ‹€νŒ¨ν•©λ‹ˆλ‹€. μ•½κ°„μ˜ μ‹€ν—˜ 후에 fs.createReadStream 둜 직접 κ΅¬μ„±λœ 슀트림만 μ—…λ‘œλ“œν•  수 μžˆλŠ” κ²ƒμ²˜λŸΌ 보이며 λ‹€λ₯Έ λͺ¨λ“  μŠ€νŠΈλ¦Όμ— λŒ€ν•΄μ„œλŠ” κ΄€λ ¨ μ—†λŠ” 였λ₯˜λ‘œ μ‹€νŒ¨ν•©λ‹ˆλ‹€.

λ‹€μŒμ€ 문제λ₯Ό μž¬ν˜„ν•˜λŠ” μ΅œμ†Œν•œμ˜ μ˜ˆμž…λ‹ˆλ‹€. PassThrough 슀트림이 formData 에 μ „λ‹¬λ˜λ©΄ λ‹€μŒ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

ERROR { Error: socket hang up
    at createHangUpError (_http_client.js:254:15)
    at Socket.socketOnEnd (_http_client.js:346:23)
    at emitNone (events.js:91:20)
    at Socket.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9) code: 'ECONNRESET' }

μ„¬κΈ°λŠ” μ‚¬λžŒ:

var http = require('http');

http.createServer(function (request, response) {                                                                                    
    request.on('data', function(chunk) {
      console.log(chunk.length);
    });    
    request.on('end', function() {
      response.writeHead(200, "OK", {'Content-Type': 'text/html'});
      response.end();
    });                                                           
}).listen(8077);

고객:

var request = require('request');
var fs = require('fs');
var PassThrough = require('stream').PassThrough;

var rs = fs.createReadStream('some_file.bin'), pt = new PassThrough();  
rs.pipe(pt);    
request({
    'method': 'POST',
    'url': 'http://127.0.0.1:8077',
    'formData': {
        'uploaded_file': pt
    }
}, function (err, httpResponse, body)
{
    if (err)
        console.log('ERROR', err);
    else
        console.log({ 'statusCode': httpResponse.statusCode, 'body': body });
});

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

버퍼λ₯Ό 직접 μ‚¬μš©ν•˜μ—¬ νŒŒμΌμ„ μ—…λ‘œλ“œν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 파일 κ΄€λ ¨ 정보(파일 이름, μœ ν˜•, ...)λ₯Ό μ§€μ •ν•˜κΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€.

var formData = {
  'file': {
    value: buffer,
    options: {
      filename: file.filename,
      contentType: file.mimetype
    }
  }
}

https://github.com/form-data/form-data#alternative -submission-methods

λͺ¨λ“  26 λŒ“κΈ€

μœ νš¨ν•œ λ©€ν‹°νŒŒνŠΈ μš”μ²­μœΌλ‘œ μ—…λ‘œλ“œν•˜κΈ° μœ„ν•΄ 읽기 μŠ€νŠΈλ¦Όμ—μ„œ Buffer λ₯Ό λž˜ν•‘ν•˜λ €κ³  ν•  λ•Œ λ™μΌν•œ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€.

λ‚˜λŠ” λ˜ν•œ 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ μ–Όλ§ˆ λ™μ•ˆ 방법을 찾으렀고 λ…Έλ ₯ν–ˆμœΌλ©° μœ„μ—μ„œ μ–ΈκΈ‰ν•œ 것과 λ™μΌν•œ 문제λ₯Ό κ²½ν—˜ν–ˆμŠ΅λ‹ˆλ‹€. λˆ„κ΅¬λ“ μ§€ 이에 λŒ€ν•œ ν•΄κ²° 방법을 μ°Ύμ•˜μŠ΅λ‹ˆκΉŒ? μ•„λ§ˆλ„ 이것은 μ‹€μ œλ‘œ form-data νŒ¨ν‚€μ§€μ˜ λ²„κ·Έμž…λ‹ˆκΉŒ?

λ™μΌν•œ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. base64 λ¬Έμžμ—΄μ΄ 있고 파일둜 보내야 ν•©λ‹ˆλ‹€. λ‚΄ base64λ₯Ό λ²„νΌλ‘œ λ³€ν™˜ν•œ λ‹€μŒ @philipp-spiess처럼 읽기 슀트림으둜 λž˜ν•‘ν•˜μ§€λ§Œ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. ν•΄κ²° 방법을 μ°ΎμœΌμ…¨λ‚˜μš”?

μ—…λ°μ΄νŠΈ: ν˜„μž¬ ν•΄κ²° 방법은 streams2λ₯Ό μ‚¬μš©ν•˜λŠ” bhttp(https://www.npmjs.com/package/bhttp)λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

버퍼λ₯Ό 직접 μ‚¬μš©ν•˜μ—¬ νŒŒμΌμ„ μ—…λ‘œλ“œν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 파일 κ΄€λ ¨ 정보(파일 이름, μœ ν˜•, ...)λ₯Ό μ§€μ •ν•˜κΈ°λ§Œ ν•˜λ©΄ λ©λ‹ˆλ‹€.

var formData = {
  'file': {
    value: buffer,
    options: {
      filename: file.filename,
      contentType: file.mimetype
    }
  }
}

https://github.com/form-data/form-data#alternative -submission-methods

@PierreCavalet , 이 방법을 μ‹œλ„ν–ˆμ§€λ§Œ λΆˆν–‰νžˆλ„ μž‘λ™ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

λ‚΄ "ν•΄κ²° 방법"은 λ‹¨μˆœνžˆ request 라이브러리λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  nodejs http μ„œλΉ„μŠ€λ₯Ό μ‚¬μš©ν•˜μ—¬ 닀쀑 λΆ€λΆ„ POSTλ₯Ό κ΅¬ν˜„ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

@PierreCavalet 버퍼가 이미 μΈμ½”λ”©λœ ν…μŠ€νŠΈμž…λ‹ˆκΉŒ? λ‚˜μ—κ²Œ λ²„νΌλŠ” μš”μ²­μ˜ 인코딩을 깨뜨린 λ°”μ΄λ„ˆλ¦¬ λΈ”λ‘­μœΌλ‘œ λ°œμƒν•©λ‹ˆλ‹€(λΆ„λͺ…νžˆ μ œλŒ€λ‘œ μΈμ½”λ”©λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ—).

νŽΈμ§‘: λΆ„λͺ…νžˆ νŠΉλ³„ν•œ 인코딩이 ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 단지 잘λͺ»λœ λΉ„νŠΈ μ˜€ν”„μ…‹μΌ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€! μ–΄μ¨Œλ“  λ‚˜λŠ” 였λ₯˜κ°€ 잘λͺ»λœ λ°”μ΄νŠΈμ— λŒ€ν•΄ λΆˆν‰ν•˜λŠ” μ„œλ²„μ˜€λ‹€λŠ” 것을 κΈ°μ–΅ν•©λ‹ˆλ‹€.

@philipp-spiess λ‚΄ λ²„νΌλŠ” λ‹€μŒμœΌλ‘œ μƒμ„±λ©λ‹ˆλ‹€.

Buffer.from(base64string, 'base64')

예, λ°”μ΄λ„ˆλ¦¬ λΈ”λ‘­μž…λ‹ˆλ‹€. μ„€λͺ…μ„œμ—λŠ” 주어진 JavaScript λ¬Έμžμ—΄μ„ ν¬ν•¨ν•˜λŠ” μƒˆ 버퍼λ₯Ό μƒμ„±ν•œλ‹€κ³  λ‚˜μ™€ μžˆμŠ΅λ‹ˆλ‹€. 제곡된 경우 인코딩 λ§€κ°œλ³€μˆ˜λŠ” λ¬Έμžμ—΄μ˜ 문자 인코딩을 μ‹λ³„ν•©λ‹ˆλ‹€.

@PierreCavalet λ‚΄κ°€ μ‚¬μš©ν•˜κ³  있던 Buffer express 파일 μ—…λ‘œλ“œ 미듀웨어 multer μ—μ„œ λ°”λ‘œ κ°€μ Έμ™”μŠ΅λ‹ˆλ‹€.

@philipp-spies μ΄μƒν•˜λ„€μš”. λ‚΄ base64 λ¬Έμžμ—΄μ€ λ²„νΌμ˜ base64 μΈμ½”λ”©μ—μ„œ κ°€μ Έμ˜€κ³  이 λ²„νΌλŠ” λ‚΄ 파일 μ—…λ‘œλ“œμ—μ„œ λ°”λ‘œ κ°€μ Έμ˜΅λ‹ˆλ‹€. (인코딩은 λ‹€λ₯Έ μ„œλΉ„μŠ€μ—μ„œ μˆ˜ν–‰ν•˜λ―€λ‘œ "아무것도"에 λŒ€ν•΄ "인코딩 및 λ””μ½”λ”©"ν•©λ‹ˆλ‹€. λ”°λΌμ„œ 그것은 λ‹Ήμ‹ μ—κ²Œλ„ νš¨κ³Όκ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

@samkelly bhttp μ‚¬μš© 을 μΆ”μ²œν•΄ μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€. 그것은 μ™„λ²½ν•˜κ²Œ μž‘λ™ν•©λ‹ˆλ‹€!

@ bchr02 예!

이 였λ₯˜ 좔적: form-data 의 _length_retriever ν•¨μˆ˜μ— λ¬Έμ œκ°€ μžˆλŠ” κ²ƒμœΌλ‘œ 판λͺ…λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 3개의 μ™„μ „νžˆ μ΄ν•΄λœ 슀트림(기본적으둜 fd ν•„λ“œκ°€ μžˆλŠ” 파일, HTTP 응닡 λ˜λŠ” μš”μ²­ 좜λ ₯ 슀트림) 쀑 ν•˜λ‚˜κ°€ μ•„λ‹Œ 슀트림이 μžˆλŠ” 경우 기본적으둜 이λ₯Ό μˆ˜ν–‰ν•˜λ €λ©΄ 양식 데이터에 거짓말을 ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ˜¬λ°”λ₯Έ 것(그리고 슀트림의 μ •ν™•ν•œ λ°”μ΄νŠΈ 길이가 ν•„μš”ν•¨). μž‘λ™μ‹œν‚€λ €λ©΄ λ‹€μŒκ³Ό 같이 ν–ˆμŠ΅λ‹ˆλ‹€.

var buffer = Buffer.from(base64string, 'base64');
buffer['httpVersion'] = true;
buffer.headers = { 'content-length': 64 }
var formData = {
  'file': {
    value: buffer,
    options: {
      filename: file.filename,
      contentType: file.mimetype
    }
  }
}

맀우 μ€‘μš”ν•©λ‹ˆλ‹€. options 에 filename ν•„λ“œλ₯Ό 지정해야 ν•©λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ λ‹€λ₯Έ μ˜ˆμ™Έκ°€ λ°œμƒν•©λ‹ˆλ‹€.

파일 μ˜΅μ…˜μ„ 지정할 수 μžˆλŠ” 경우 파일 슀트림의 λ°”μ΄νŠΈ 길이둜 options.knownLength λ₯Ό 지정할 수 μžˆμ–΄μ•Ό ν•˜λ©° FormDataμ—μ„œ μ„ νƒν•©λ‹ˆλ‹€.

μ‹€μ œλ‘œ 많이 κ³΅κ°œλ˜μ§€λŠ” μ•Šμ•˜μ§€λ§Œ FormData의 μΆ”κ°€ 정보 에 μ–ΈκΈ‰λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. λ‚΄κ°€ 말할 μˆ˜μžˆλŠ” μ§€κΈˆκΉŒμ§€ μš”μ²­μ€ 어디에도 μ–ΈκΈ‰ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ•„, νš¨κ³Όκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. μƒˆλ²½ 2μ‹œμ— 디버깅을 ν•˜λ„λ‘ κ°€λ₯΄μ³ μ£Όμ„Έμš”. λ‚˜λŠ” knownLengthλ₯Ό μ‹œλ„ν–ˆμ§€λ§Œ μ˜ˆμ™Έκ°€ λ°œμƒν–ˆλ‹€κ³  λ§Ήμ„Έν•  수 μžˆμ§€λ§Œ, 파일 이름 ν•„λ“œκ°€ λΆ€μ‘±ν•˜μ—¬ 혼돈이 λ°œμƒν–ˆμ„ 수 μžˆμŠ΅λ‹ˆλ‹€.

이것은 gzip 슀트림의 일뢀인 것을 μ—…λ‘œλ“œν•˜κ³  μžˆμœΌλ―€λ‘œ 길이λ₯Ό λͺ¨λ₯΄κΈ° λ•Œλ¬Έμ— λ‚΄ μƒν™©μ—μ„œλŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

@ sam0x17 μ‹€μ œλ‘œ λ‚΄κ°€ 말할 μˆ˜μžˆλŠ” ν•œ requestλŠ” ν˜„μž¬ transfer-encoding: chunked μ§€μ›ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ bhttpλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ˜ν•œλ³΄μ‹­μ‹œμ˜€

ν‘œμ‹œ

λ™μΌν•œ λ¬Έμ œμ— μ§λ©΄ν–ˆμŠ΅λ‹ˆλ‹€. 여기에 직접 http λͺ¨λ“ˆμ„ μ‚¬μš©ν•˜λŠ” ν•΄κ²° 방법이 μžˆμŠ΅λ‹ˆλ‹€.

const streamSample = fs.createReadStream('data.csv').pipe(passThrough);

const formHTTP = new FormData();
formHTTP.append('sampleFieldText', 'text-sample');
formHTTP.append('myFile', streamSample);

const requestToSend = http.request({
    method: 'post',
    host: 'localhost',
    path: '/http',
    headers: formHTTP.getHeaders()
});

formHTTP.pipe(requestToSend);

requestToSend.on('response', (res) => {
    console.log('HTTP response', res.statusCode);
});

requestToSend.on('error', (e) => {
    console.log('ERROR HTTP', e);
});

@BenjD90
ν•΄κ²° 방법을 μ‚¬μš©ν–ˆμ§€λ§Œ 슀트림이 μ „ν˜€ μ „μ†‘λ˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆλ‹€. 관련성이 μžˆλŠ” 경우 μˆ˜μ‹  μΈ‘μ—μ„œ multerλ₯Ό μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

@Ncifra ν˜„μž¬ ν”„λ‘œμ νŠΈμ—μ„œ 맀일 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— ν•΄κ²° 방법이 νš¨κ³Όκ°€ μžˆλ‹€κ³  ν™•μ‹ ν•©λ‹ˆλ‹€.
https://beeceptor.com/μ—μ„œ μŠ€νŠΈλ¦Όμ„ ν…ŒμŠ€νŠΈν•  수 μžˆμŠ΅λ‹ˆλ‹€. ;)

λ‚˜λŠ” μ‹€μ œλ‘œ 이것을 λ‹€μŒκ³Ό 같이 ν•΄κ²°ν–ˆμŠ΅λ‹ˆλ‹€. https://github.com/form-data/form-data/issues/356#issue -234978025
λ¬Έμ œμ™€ κ΄€λ ¨λœ λ‚΄ μ›λž˜ λ¬Έμ œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€. https://github.com/form-data/form-data/issues/409

@BenjD90 ν˜„μž¬ μž‘μ—… 쀑인 ν”„λ‘œμ νŠΈμ—μ„œ 맀우 μ§€μ—°λœ κΈ°λŠ₯μ΄μ—ˆκΈ° λ•Œλ¬Έμ— μ½”λ“œλ₯Ό 되돌렸고 ν…ŒμŠ€νŠΈν•  수 μ—†μŠ΅λ‹ˆλ‹€. λͺ¨λ“  ν…ŒμŠ€νŠΈκ°€ λ„ˆλ¬΄ λ§Žμ€ ν¬μ†Œ μ½”λ“œλ₯Ό μƒμ„±ν–ˆκΈ° λ•Œλ¬Έμ— λ‚΄κ°€ λ­”κ°€λ₯Ό λ†“μΉ˜κ³  μžˆμ—ˆμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜λ„ μš”μ²­μ„ κΈ°λ‘ν–ˆκ³  양식 데이터 κ°œμ²΄μ— 파일이 μžˆλŠ” 것 κ°™μ•˜μ§€λ§Œ λ‹€λ₯Έ λΉ„ λ°”μ΄λ„ˆλ¦¬ 데이터가 μ˜¬λ°”λ₯΄κ²Œ μ „μ†‘λ˜λŠ” λ™μ•ˆ multerλŠ” νŒŒμΌμ„ 받지 λͺ»ν•œ 것 κ°™μŠ΅λ‹ˆλ‹€.

이 λ¬Έμ œλŠ” 졜근 ν™œλ™μ΄ μ—†μ—ˆκΈ° λ•Œλ¬Έμ— μžλ™μœΌλ‘œ 였래된 κ²ƒμœΌλ‘œ ν‘œμ‹œλ˜μ—ˆμŠ΅λ‹ˆλ‹€. 더 이상 ν™œλ™μ΄ μ—†μœΌλ©΄ νμ‡„λ©λ‹ˆλ‹€. κ·€ν•˜μ˜ 기여에 κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

@stale 이 λ²„κ·ΈλŠ” κ°•μ²  쑴재이며 당일 μˆ˜μ •λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€^^

예, λ™μ˜ν–ˆμŠ΅λ‹ˆλ‹€. κ·Έλ•Œλ§ŒνΌ μ§€κΈˆμ΄ μ€‘μš”ν•©λ‹ˆλ‹€. λ‚˜λŠ” 기본적으둜 bhttp λŒ€μ‹  request λ₯Ό λ‹€μ‹œ μ‚¬μš©ν•˜κΈ° 전에 이것이 μˆ˜μ •λ˜κΈ°λ₯Ό 기닀리고 μžˆμŠ΅λ‹ˆλ‹€. 이것은 streams 및 streams2 API의 κΈ°λ³Έ κΈ°λŠ₯이며 request μ—μ„œ μ™„μ „νžˆ μ§€μ›λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰