POSTだけでなく、PUTリクエストを使ってファイルをアップロードすることもできる。
PUTリクエストでは1回のリクエストに1つのファイルしか送れないが、ファイルストリームを直接サーバに送るだけでことが済み、サーバサイドでリクエストをパースする必要がない。
ので、サーバサイドでの処理が楽になる。
HTMLファイル側でformのmethod属性をPOSTからPUTに変更するだけでこれが実現できれば良いのだが…残念ながらHTMLの基準のformではPUTメソッドを使用できない。ただし、現在策定中のXMLHttpRequest level2(xhr2)では、JavaScriptを使ってPUTメソッドでバイナリデータを送信することができる。
XMLHttpRequestを使ってPUTリクエストでファイルアップロードを実践してみる。
put_upload.htmlとserver.jsとアップロードファイルを保持するuploadsディレクトリを作成する。
put_upload.html
(put_upload.html)
input#userfileのchangeイベントを受け取ると、file変数でファイルポインタを取得する。そして、xhrでPUTリクエストを発行する。
この例では、1回のリクエストでファイルを1つだけ送信しているが、拡張して複数のファイルを非同期で一度にサーバに転送することも可能。
このコードではまず、ファイルを選択するinput要素にchangeイベントリスナを与えて、ユーザがファイルを選択した時点でファイルポインタを取得する。フォームがsubmitされると、デフォルトのフォームアクションを無効化して、XMLHttpRequestオブジェクトを生成しPUTリクエストをサーバに送るように設定する。また、サーバがファイル名を認識できるよう、カスタムヘッダを付与する。
(server.js)
このサーバはリクエストのdataイベントを待ち、送信されるchunkをまとめている。だたし、ここではデータ文字列を結合する方法はとっておらず、Bufferオブジェクトを生成してバッファ内でchunkを結合している。バイナリデータを取り扱う際に文字列タイプを使ってしまうと、データの結合時にデータ内容を破壊してしまうが、Bufferオブジェクトはバイナリを含めてどのようなデータタイプも取り扱うことができる。
リクエストのendイベントが発行されると、formidableと同様のランダムなファイル名を付与してuploadsフォルダに格納する。
Nodeクックブック p.41
PUTリクエストでは1回のリクエストに1つのファイルしか送れないが、ファイルストリームを直接サーバに送るだけでことが済み、サーバサイドでリクエストをパースする必要がない。
ので、サーバサイドでの処理が楽になる。
HTMLファイル側でformのmethod属性をPOSTからPUTに変更するだけでこれが実現できれば良いのだが…残念ながらHTMLの基準のformではPUTメソッドを使用できない。ただし、現在策定中のXMLHttpRequest level2(xhr2)では、JavaScriptを使ってPUTメソッドでバイナリデータを送信することができる。
XMLHttpRequestを使ってPUTリクエストでファイルアップロードを実践してみる。
put_upload.htmlとserver.jsとアップロードファイルを保持するuploadsディレクトリを作成する。
put_upload.html
<html>
<body>
<form id="form">
<input type="file" id="userfile" name="userfile"><br>
<input type="submit">
</form>
<script>
(function(){
var userfile = document.getElementById('userfile'),
form = document.getElementById('form'),
file;
userfile.addEventListener('change',function(){
file = this.files[0];
});
form.addEventListener('submit',function(e){
e.preventDefault();
if(file){
var xhr = new XMLHttpRequest();
xhr.file = file;
xhr.open('put',window.location,true);
xhr.setRequestHeader('x-uploadedfilename',file.fileName || file.name);
xhr.send(file);
file = '';
form.reset();
}
});
})();
</script>
</body>
</html>
server.js
server.js
var http = require('http');
var fs = require('fs');
var form = fs.readFileSync('put_upload.html');
http.createServer(function (req,res){
if(req.method === 'GET'){
res.writeHead(200,{'Content-Type': 'text/html'});
res.end(form);
}
if(req.method === 'PUT'){
var fileData = new Buffer(+req.headers['content-length']);
var bufferOffset = 0;
req.on('data',function(chunk){
chunk.copy(fileData,bufferOffset);
bufferOffset += chunk.length;
}).on('end',function(){
var rand = (Math.random() * Math.random()).toString(16).replace('.','');
var to = 'uploads/' + rand + '-' +req.headers['x-uploadedfilename'];
fs.writeFile(to,fileData,function(err){
if(err){throw err;}
console.log('ファイルを' + to + 'に保存しました');
res.end();
});
});
}
}).listen(8080);
(put_upload.html)
input#userfileのchangeイベントを受け取ると、file変数でファイルポインタを取得する。そして、xhrでPUTリクエストを発行する。
この例では、1回のリクエストでファイルを1つだけ送信しているが、拡張して複数のファイルを非同期で一度にサーバに転送することも可能。
このコードではまず、ファイルを選択するinput要素にchangeイベントリスナを与えて、ユーザがファイルを選択した時点でファイルポインタを取得する。フォームがsubmitされると、デフォルトのフォームアクションを無効化して、XMLHttpRequestオブジェクトを生成しPUTリクエストをサーバに送るように設定する。また、サーバがファイル名を認識できるよう、カスタムヘッダを付与する。
(server.js)
このサーバはリクエストのdataイベントを待ち、送信されるchunkをまとめている。だたし、ここではデータ文字列を結合する方法はとっておらず、Bufferオブジェクトを生成してバッファ内でchunkを結合している。バイナリデータを取り扱う際に文字列タイプを使ってしまうと、データの結合時にデータ内容を破壊してしまうが、Bufferオブジェクトはバイナリを含めてどのようなデータタイプも取り扱うことができる。
リクエストのendイベントが発行されると、formidableと同様のランダムなファイル名を付与してuploadsフォルダに格納する。
Nodeクックブック p.41