[JavaScript] ブラウザからSuperAgentでファイルをPOST

ブラウザからSuperAgentでファイルをPOSTしようとしてハマったのでメモ。なお、SuperAgentAJAX通信に特化した軽量なJavaScriptライブラリです。

SuperAgent紹介記事リンク:jQuery.ajaxの代わりにSuperAgentを使う - Qiita

ハマった部分

まず、HTMLでformのsubmitを使ってファイルを送る場合は次のようになります。enctype="multipart/form-data"が唯一ポイントで、後はtype=fileなinputを利用するだけです。

<form name="main_form" action="/some-url" enctype="multipart/form-data" method="POST">
  <input name="submit_file" type="file">
  <input type="submit" value="ファイル送信">
</form>

もう少し柔軟に制御したかったのでSuperAgentで自分でAJAX通信をしようと思いました。そこでドキュメントを見ると、ファイルを送るには.attach(name, [path], [filename])関数を使うように書いてあります。

// SuperAgentのドキュメントから引用
 request
   .post('/upload')
   .field('user[name]', 'Tobi')
   .field('user[email]', 'tobi@learnboost.com')
   .attach('image', 'path/to/tobi.png')
   .end(callback);

第2引数のpathって何さと思い、フルパスを渡してみたりと色々的はずれな試行錯誤をしていました。しかし、どうやらこの記述はNode.jsすなわちサーバ側で利用する場合の説明であって、ブラウザ側ではまた違うものを渡す必要があるようです。

そしてそのブラウザ側での話は書かれていない(はず)…。

結論

結局どうするかですが、Fileオブジェクトを渡せば良いようです。冒頭のformを例に取ると、Fileオブジェクトは下記のように取り出せます。

document.main_form.submit_file.files[0]

実際、SuperAgentのソースで.attach()関数のコメントを見るとFileオブジェクトかBlobオブジェクトを渡せと書いてあります。

引用元:https://cdnjs.cloudflare.com/ajax/libs/superagent/1.2.0/superagent.js

/**
 * Queue the given `file` as an attachment to the specified `field`,
 * with optional `filename`.
 *
 * ``` js
 * request.post('/upload')
 *   .attach(new Blob(['<a id="a"><b id="b">hey!</b></a>'], { type: "text/html"}))
 *   .end(callback);
 * ```
 *
 * @param {String} field
 * @param {Blob|File} file
 * @param {String} filename
 * @return {Request} for chaining
 * @api public
 */

…なんとなく尻切れ感がありますが、他に書きたいこともないので終わり。