Request: تحميل الملف يعمل فقط مع تدفقات القراءة القياسية

تم إنشاؤها على ٢٨ ديسمبر ٢٠١٦  ·  26تعليقات  ·  مصدر: request/request

كنت أحاول تحميل ملف (باستخدام طلب POST متعدد الأجزاء) موجود داخل أرشيف TAR (أستخدم مكتبة 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- طرق

ال 26 كومينتر

أواجه نفس المشكلة عندما أحاول تغليف Buffer في دفق قراءة لتحميله كطلب صالح متعدد الأجزاء.

لقد كنت أحاول أيضًا إيجاد طريقة للتغلب على هذه المشكلة لبعض الوقت وشهدت نفس المشكلات المذكورة أعلاه. هل وجد أي شخص حلا لهذا؟ ربما هذا هو في الواقع خطأ في نموذج البيانات الحزمة؟

نفس المشكلة هنا ، لدي سلسلة base64 وأحتاج إلى إرسالها كملف. أقوم بتحويل base64 الخاص بي إلى مخزن مؤقت ثم ، تمامًا مثل @ philipp-spiess ، أقوم بلفه في دفق قراءة ، لكنه لا يعمل. هل وجدتم عملًا قريبًا يا رفاق؟

التحديث: في الوقت الحالي ، يستخدم الحل البديل bhttp (https://www.npmjs.com/package/bhttp) الذي يستخدم Streams2

تمكنت من تحميل ملفي باستخدام المخزن المؤقت مباشرة. تحتاج فقط إلى تحديد المعلومات المتعلقة بالملف (اسم الملف ، النوع ، ...)

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

https://github.com/form-data/form-data#alternative -submission- طرق

PierreCavalet ، لقد حاولت بهذه الطريقة ولكن للأسف لم تنجح.

كان "الحل البديل" الخاص بي ببساطة هو عدم استخدام مكتبة request وتنفيذ POST متعدد الأجزاء باستخدام خدمة http nodejs.

PierreCavalet هل المخزن المؤقت الخاص بك بالفعل نص مشفر؟ بالنسبة لي ، كان المخزن المؤقت عبارة عن نقطة ثنائية أدت إلى كسر تشفير الطلب (نظرًا لأنه لم يتم ترميزه بشكل صحيح على ما يبدو).

تحرير: يبدو أنه ليس هناك حاجة إلى ترميز خاص ، ربما مجرد إزاحة خاطئة ؟! على أي حال أذكر أن الخطأ كان الخادم يشكو من بايت غير صالح.

@ philipp-spiess تم إنشاء المخزن المؤقت الخاص بي باستخدام:

Buffer.from(base64string, 'base64')

لذا نعم إنها نقطة ثنائية. تشير الوثائق إلى أنها تنشئ مخزنًا مؤقتًا جديدًا يحتوي على سلسلة JavaScript المحددة. إذا تم توفيره ، فإن معلمة التشفير تحدد ترميز أحرف السلسلة.

PierreCavalet كان Buffer الذي كنت أستخدمه مباشرة من multer ، وهو برنامج وسيط لتحميل الملفات مقابل express .

@ philipp-spiess هذا غريب. تأتي سلسلة base64 الخاصة بي من تشفير base64 لمخزن مؤقت ، وهذا المخزن المؤقت مباشرة من تحميل الملف الخاص بي. (يتم إجراء التشفير بواسطة خدمة أخرى ، ولهذا السبب نقوم "بالتشفير وفك التشفير" مقابل "لا شيء"). لذلك يجب أن تعمل من أجلك أيضًا.

samkelly شكرا جزيلا لك على توصيتك باستخدام bhttp . إنه يعمل بشكل مثالي!

@ bchr02 على سبيل المثال!

تم تتبع هذا الخطأ لأسفل: تبين أنها مشكلة في دالة _length_retriever لبيانات النموذج. إذا كان لديك دفق ليس واحدًا من التدفقات الثلاثة المفهومة تمامًا (بشكل أساسي الملفات التي تحتوي على حقل 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
    }
  }
}

مهم جدًا: يجب تحديد الحقل filename في options ، وإلا فستحصل على استثناء آخر.

إذا كان بإمكانك تحديد خيارات الملف ، فيجب أن تكون قادرًا على تحديد options.knownLength بطول بايت دفق الملف الخاص بك وسيتم التقاطه بواسطة FormData.

تم ذكره في الملف التمهيدي لـ FormData على الرغم من أنه لم يتم نشره كثيرًا. لم يذكر الطلب ذلك في أي مكان الآن حتى الآن أستطيع أن أقول.

آه ، لقد نجح ذلك: علمني أن أقوم بأي تصحيح في الساعة 2 صباحًا. كان من الممكن أن أقسم أنني حاولت knownLength وحصلت على استثناء ، لكن ربما كان ذلك بسبب عدم وجود حقل اسم الملف الذي تسبب في حدوث فوضى.

هذا لا يعمل مع وضعي ، لأنني أقوم بتحميل شيء ما هو جزء من دفق gzip ، لذلك لا أعرف الطول.

@ sam0x17 في الواقع ، لن يكون الأمر كذلك ، بقدر ما أستطيع أن أقول ، الطلب لا يدعم حاليًا 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);
});

تضمين التغريدة
لقد استخدمت الحل البديل الخاص بك ، ولكن يبدو أن البث لم يتم إرساله على الإطلاق. أنا أستخدم 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 هذا الخطأ موجود من الفولاذ ويجب إصلاحه في اليوم ^^

نعم موافق ، إنها مهمة الآن كما كانت في ذلك الوقت. لقد كنت في الأساس في انتظار إصلاح هذا قبل استخدام request مرة أخرى بدلاً من bhttp . هذه ميزة أساسية لواجهة برمجة تطبيقات Streams2 API ويجب دعمها بالكامل بواسطة request .

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

IgorDePaula picture IgorDePaula  ·  3تعليقات

victor0402 picture victor0402  ·  4تعليقات

ghost picture ghost  ·  3تعليقات

xin7c picture xin7c  ·  3تعليقات

ghost picture ghost  ·  3تعليقات