web-dev-qa-db-ja.com

Node.jsでPOSTリクエストを使用してファイルをアップロードする

Node.jsでPOSTリクエストを使用してファイルをアップロードする際に問題があります。 requestモジュールを使用してそれを達成する必要があります(外部npmはありません)。サーバーは、ファイルのデータを含むfileフィールドを持つマルチパートリクエストである必要があります。 Node.jsで外部モジュールを使用せずに実行するのは非常に難しいと思われる簡単なことです。

この例 を使用しようとしましたが、成功しませんでした:

request.post({
  uri: url,
  method: 'POST',
  multipart: [{
    body: '<FILE_DATA>'
  }]
}, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
66
Jagi

すでに request module を使用しているようです。

この場合、multipart/form-dataを投稿する必要があるのは、その form機能 を使用することだけです。

var req = request.post(url, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
var form = req.form();
form.append('file', '<FILE_DATA>', {
  filename: 'myfile.txt',
  contentType: 'text/plain'
});

ただし、既存のファイルをファイルシステムから投稿する場合は、読み取り可能なストリームとして渡すだけです。

form.append('file', fs.createReadStream(filepath));

requestは、関連するすべてのメタデータを単独で抽出します。

multipart/form-dataの投稿の詳細については、 node-form-data module を参照してください。これはrequestによって内部的に使用されます。

89

formDataが実装するrequestフィールドの文書化されていない機能は、使用するform-dataモジュールにオプションを渡す機能です。

request({
  url: 'http://example.com',
  method: 'POST',
  formData: {
    'regularField': 'someValue',
    'regularFile': someFileStream,
    'customBufferFile': {
      value: fileBufferData,
      options: {
        filename: 'myfile.bin'
      }
    }
  }
}, handleResponse);

これは、requestObj.form()の呼び出しを避ける必要があるが、バッファをファイルとしてアップロードする必要がある場合に役立ちます。 form-dataモジュールは、contentType(MIMEタイプ)およびknownLengthオプションも受け入れます。

この変更 は2014年10月に追加されたため(この質問が出されてから2か月後)、今は安全に使用できるはずです(2017年以降)。これは、requestのバージョンv2.46.0以上に相当します。

18
Clavin

Leonid Beschastnyの答えは機能しますが、ArrayBufferをNodeのrequestモジュールで使用されるBufferに変換する必要もありました。サーバーにファイルをアップロードした後、HTML5 FileAPI(Meteorを使用しています)から来たのと同じ形式でファイルを入手しました。以下の完全なコード-他の人に役立つかもしれません。

function toBuffer(ab) {
  var buffer = new Buffer(ab.byteLength);
  var view = new Uint8Array(ab);
  for (var i = 0; i < buffer.length; ++i) {
    buffer[i] = view[i];
  }
  return buffer;
}

var req = request.post(url, function (err, resp, body) {
  if (err) {
    console.log('Error!');
  } else {
    console.log('URL: ' + body);
  }
});
var form = req.form();
form.append('file', toBuffer(file.data), {
  filename: file.name,
  contentType: file.type
});
4
Jagi

リクエストライブラリの「カスタムオプション」サポートを使用することもできます。この形式を使用すると、マルチパートのフォームアップロードを作成できますが、ファイルと、ファイル名やコンテンツタイプなどの追加のフォーム情報の両方のエントリが組み合わされています。一部のライブラリ、特にmulterなどのライブラリは、この形式を使用してファイルのアップロードを受信することを期待していることがわかりました。

このアプローチは、リクエストドキュメントのフォームセクションに正式に文書化されています- https://github.com/request/request#forms

//toUpload is the name of the input file: <input type="file" name="toUpload">

let fileToUpload = req.file;

let formData = {
    toUpload: {
      value: fs.createReadStream(path.join(__dirname, '..', '..','upload', fileToUpload.filename)),
      options: {
        filename: fileToUpload.originalname,
        contentType: fileToUpload.mimeType
      }
    }
  };
let options = {
    url: url,
    method: 'POST',
    formData: formData
  }
request(options, function (err, resp, body) {
    if (err)
      cb(err);

    if (!err && resp.statusCode == 200) {
      cb(null, body);
    }
  });
4