1. はじめに
今回はajaxでマルチパートを使わずにファイルをアップロードする方法について説明したいと思います。
(ポイント)
- JQueryなどの外部ライブラリは利用せず、素のJavaScriptのみで実現する
-
XMLHttpRequest
とFile(Blob)
を利用する -
multipart/form-data
ではなく、ファイル種別に応じた任意のcontent-type
でデータを送信する - HTTPリクエストのBODYはファイルデータそのもの(バイナリ)となり、
multipart/form-data(たとえばbase64)
のエンコード、デコード処理が不要となる - サーバ側のアップロード処理がこの方法に対応している必要がある
2. ソースコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>upload</title>
</head>
<body>
<div id="wrapper">
<div>
<input id="uploadFile" type="file" />
</div>
<div>
<input id="uploadButton" type="button" value="送信" />
</div>
<div>
<p id="message">ファイルを選択して「送信」ボタンを押してください。</p>
</div>
<div>
<progress id="uploadProgress" max="100" value="0"></progress>
</div>
</div>
<script type="text/javascript">
<!--
(function() {
var post_file = function(upload_file) {
var maeesage = document.getElementById("message");
maeesage.innerHTML = "アップロード中です。";
// ★ポイント1
var content_length = upload_file.size
var content_type = upload_file.type
var file_name = upload_file.name;
// ★ポイント2
var xhr = new XMLHttpRequest();
xhr.open('POST', '/todo-rest/upload/chunked', true);
xhr.setRequestHeader('Content-type', content_type);
xhr.setRequestHeader('Content-Length', content_length);
xhr.setRequestHeader('X-FILE-NAME', file_name);
// ★ポイント3
xhr.onload = function(e) {
if (this.readyState == 4) {
maeesage.innerHTML = "アップロードが完了しました。";
}
};
// ★ポイント4
var progress = document.getElementById("uploadProgress");
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progress.value = (e.loaded / e.total) * 100;
}
};
// ★ポイント5
xhr.send(upload_file);
};
// ★ポイント6
document.getElementById("uploadButton").addEventListener(
'click',
function() {
var element_file = document
.getElementById("uploadFile");
var upload_file = element_file.files[0];
post_file(upload_file);
}, false);
})();
-->
</script>
</body>
</html>
★ポイント1
File
オブジェクトから各種ファイルの情報を取得します。
今回は①ファイル名、②ファイルサイズ(バイト単位)、③mimeタイプを取得します。
詳細については「 https://developer.mozilla.org/ja/docs/Web/API/File 」を参照ください。
★ポイント2
XMLHttpRequest
オブジェクトを生成し、HTTPヘッダ等の必要な情報を設定します。
はじめにでも説明しましたがcontent-type
はmultipart/form-data
ではなく★ポイント1で取得したファイルのものを設定します。
★ポイント3
XMLHttpRequest
のonload
プロパティにアップロード完了時に実行するコールバック処理を記述します。
★ポイント4
今回の記事の本質ではありませんが、折角なのでアップロードの進行状況をプログレスバーで表示するようにしてみました。
XMLHttpRequest
のupload.onprogress
プロパティにアップロード中に実行するコールバック処理を記述します。
★ポイント5
XMLHttpRequest
のsend()
メソッドにFile
オブジェクトを設定し、HTTPリクエストを発行します。
詳細については「 https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest#send() 」を参照ください。
★ポイント6
「送信」ボタンが押された際にアップロード処理が実行されるようにclick
イベントにリスナーを登録します。
input type="file"
では複数のファイルの選択も可能なため、1つ目のFile
オブジェクトを選択します。
詳細については「 https://developer.mozilla.org/ja/docs/Web/API/FileList 」を参照ください。
3. さいごに
今回はajaxでマルチパートを利用しないでファイルをアップロードする方法について説明しました。
ファイルダウンロードの場合、HTTPレスポンスのBODYはファイルのバイナリデータのみが格納されているため、アップロードでも同じデータ構成でもおかしくないのではないでしょうか。
デメリットとしてはサーバ側もこれに対応した実装が必要となることです。テストでは400MB弱のファイルを6秒でアップロードすることができました。
ファイルアップロード=multipart/form-data
というイメージがありますが、必ずしもそうとは限らないというのを理解して頂けたかと思います。