input[type="file"]をAjaxで送信したい時
普通にAjaxを使って送ると、ファイルが文字列になってしまい
form.submit()した時と違うのでハマったのでメモ。
どうやら FormData を使い
Ajaxが自動的に送信データを整形する機能をOFFにすれば
form.submit()と同じデータで送れるようです。
■ フォーム
<form id="myForm" name="myForm" method="post" action=""> <input type="file" name="file" id="formFile"/> <input type="text" name="text" id="formText"/> <textarea name="textarea" id="formTextarea"></textarea> <input type="submit" id="submitBtn" value="そうしん!" /> </form>
$(function() { $('#submitBtn').on('click', function(evt) { var form = $('#myForm').get()[0]; // FormData オブジェクトを作成 var formData = new FormData( form ); // Ajaxで送信 $.ajax({ url: '/api' method: 'post', dataType: 'json', // dataに FormDataを指定 data: formData, // Ajaxがdataを整形しない指定 processData: false, // contentTypeもfalseに指定 contentType: false }).done(function( res ) { // 送信せいこう! console.log( 'SUCCESS', res ); }).fail(function( jqXHR, textStatus, errorThrown ) { // しっぱい! console.log( 'ERROR', jqXHR, textStatus, errorThrown ); }); return false; }); });
processData: false
とcontentType: false
がポイントの様です。
new FormData()する時にformを渡してやると
form.submit();した時と同じ様に
フォーム内のデータがnameとvalueのセットでそのまま送信されます。
nameを変更して送りたい時は次のように指定することが出来ます。
$(function() { $('#submitBtn').on('click', function(evt) { // FormData オブジェクトを作成 var formData = new FormData(); var $text = $('#formText'); var $textarea = $('#formTextarea'); var $file = $('#formFile'); // appendを使いnameとデータをセット formData.append( 'form-text', $text.val() ); // attr('name')を使えばHTMLで指定されているnameのまま送れる formData.append( $textarea.attr('name'), $textarea.val() ); // fileは .prop() で files を取ってきてセットする formData.append( $file.attr('name'), $file.prop("files")[0] ); // Ajaxで送信 $.ajax({ url: '/api' method: 'post', dataType: 'json', data: formData, processData: false, contentType: false }).done(function( res ) { console.log( 'SUCCESS', res ); }).fail(function( jqXHR, textStatus, errorThrown ) { console.log( 'ERROR', jqXHR, textStatus, errorThrown ); }); return false; }); });
フォームに入力されてないならAjaxでデータを送らない。
などといった処理を入れる場合はこちらの方が使うかも?
[参考にしました]
・jQuery.ajax() | jQuery API Documentation
・jQuery + ajax で ファイルアップロードするには - 犬ターネット
・y.okano blog: jQuery.ajax() でファイルを送る
少しズレるのだけれど、
AjaxはContent-Typeが指定できるっぽいです。
contentType falseで送るのが気持ち悪いって時に使えるかも。
$(function() { /* 中略 */ $.ajax({ url: '/api' method: 'post', dataType: 'json', data: formData, processData: false, // headers を使ってContent-Typeを指定 headers: { 'Content-Type': 'multipart/form-data' } }).done(function( res ) { console.log( 'SUCCESS', res ); }).fail(function( jqXHR, textStatus, errorThrown ) { console.log( 'ERROR', jqXHR, textStatus, errorThrown ); }); /* 中略 */ });
contentTypeプロパティもあるので、headersを使わずに
contentType: 'multipart/form-data'
みたいな指定でもOKっぽい!
[参考にしました]
・jQuery: ajax メソッドのヘッダーを変更する - Sarabande.jp
ただし、
このFormDataってのがHTML5のものらしく、
IE9以前、Android2.3系以前のバージョンでは使えないらしい。
これらに対応せざるをえない時はFormData判定して処理分けるしかなさそう。。。
// FormData に対応しているか判定 if(window.FormData) { // FormData 使えるのでAjaxで送信 } else { // FormData 使えない子なので、form.submit()で対応? }
[参考にしました]
・JavaScriptプログラミング講座【FormData クラスについて】
・Ajaxによるmultipart/postでの画像ファイルアップロード : アシアルブログ のコメント欄

- 作者: 白岩登
- 出版社/メーカー: 株式会社フェンドーラ
- 発売日: 2014/01/19
- メディア: Kindle版
- この商品を含むブログを見る