HTML5 File API & XHR2 with Node.js Express
Note: This article is written in Japanese for 東京Node学園祭2012. I may or may not re-post this in English later only when I feel like to.
KTHXBAI
こんにちは、そして(たぶん)はじめまして。GirlieMac! Blog 初の日本語の記事を「東京Node学園祭」のために書かせてもらう事になりました。私はサンフランシスコ在住なので残念ながら学園祭参加はできないのですが、ブログの参加で遠く離れたこの地で応援されていただきます。
先に説明しておきますが、私はフロントエンド、しかもモバイルの UX ディベロッパーなので Node.js の記事というとちょっと畑違いかもしれませんが、フロントエンド目線で HTML5 File API と XHR2 そして Node を一緒に使ってみた画像ファイルアップロードのチュートリアルを書いてみます。
ここで使われた HTML5 フィーチュアはまだブラウザによってはサポートされていません。したがってコンパティビリティについては Can I use File API? と、Can I use XHR2? でチェックしてみてください。
それでは、HTML5 File API を使って画像のローカルファイルを読み込んでみましょう。
まず、HTML マークアップ側で、フォームを作成します。
<input type="file">
エレメントを使います。ここでは、accept
属性を image/*
と指定して画像ファイルのみを扱ってみましょう。
<form id="uploadForm" enctype="multipart/form-data" method="post" action="/upload">
<input type="file" accept="image/*" name="imagefile" id="imagefile">
<input type="button" value="Upload" id="upoadButton">
</form>
<img id="preview">
JavaScript 側です。ユーザが画像を選択した際に File
オブジェクトのリストを返します。
document.getElementById('imagefile').addEventListener('change', function() {
fileSelected();
}, false);
FileReader
オブジェクトをインスタンスとして読み取ります。
さてここで、readAsDataURL()
を呼び、 DataURL
を使ってアップロード前に画像プレビューを表示してみましょう。
function fileSelected() {
var localFile = document.getElementById('imagefile').files[0];
var imgFmt = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
if (!imgFmt.test(localFile.type)) {
... // 画像ファイルではありません、というエラーメッセージなど
}
var preview = document.getElementById('preview');
// 画像ファイルを data URL として読み取ります
var reader = new FileReader();
reader.readAsDataURL(localFile);
reader.onload = function(e){
// e.target.result は DataURL を含みます
preview.src = e.target.result;
}
}
XMLHttpRequest オブジェクトを作ります。次のイベント(progress, load, error, abort)のイベントリスナーを登録し、XMLHttpRequest Level 2 でサポートされ始めた FormData を使ってデータを send() メソッドで POST します。
document.getElementById('upoadButton').addEventListener('click', function() {
startUpload();
}, false);
function startUpload() {
var formData = new FormData(document.getElementById('uploadForm'));
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', uploadProgress, false);
xhr.addEventListener('load', uploadFinish, false);
xhr.addEventListener('error', uploadError, false);
xhr.addEventListener('abort', uploadAbort, false);
xhr.open('POST', '/upload');
xhr.send(formData);
}
function uploadProgress() { ... }
さて、ここでやっと、Node.js の登場です。 Express を使ってファイルを指定先にアップロードしましょう。
アップロードされたファイルの情報は req.files に含まれています。例えばファイルサイズ (byte) の情報は size プロパティ、ファイル名は name プロパティ、といった感じです。
app.js Server-side:
/* Server configuration */
app.configure(function(){
app.use(express.methodOverride());
app.use(express.bodyParser({keepExtensions: true}));
app.use(express.static(__dirname + '/public'));
});
var fs = require('fs');
app.post('/upload', function(req, res) {
// 仮のファイル置き場
var tmp_path = req.files.imagefile.path;
// 実際のファイル置き場
var target_path = './public/user/' + req.files.imagefile.name;
// ファイルを仮の場所から移します
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// 仮ファイルを削除します
fs.unlink(tmp_path, function() {
if (err) throw err;
res.send('File uploaded to: ' + target_path + ' - ' + req.files.imagefile.size + ' bytes');
});
});
});
と、こんな感じです。かなりはしょりましたが大まかな流れがわかっていただけたでしょうか。
久々の日本語のブログでちょっと手こずってしまいましたが、楽しんでいただけたら幸いです。コードや説明に間違いを見つけたり感想があった場合は遠慮なくコメントください。コメントはスパム防止のために承認制にしてあるのですが時差もあるのでちょっと遅れるかもしれません。
References
- W3C: File API
- W3C: XMLHttpRequest Level 2 – FormData インターフェイス
- Node.js: Express
- Article: Handle File Uploads in Express
comments powered by