最近Backbone.jsを使い始めました。
JavaScriptのMVCフレームワークの内、知名度が最も高いらしいということで。
日本語の入門記事としてはこちらが非常に分かりやすく、参考にさせていただいています。
Backbone.js 入門
Model.save()のサンプル
Backbone.jsのModelを使ってデータ登録・更新を行う場合、通常はModelメソッドのsave() を使うと思いますが、save()の動作を確認する簡単なサンプルを作ってみました。
(save()を使うと、リソースAPIに対してPOST(またはPUT)リクエストが送信されます。)
サンプルの動作
- 「送信」ボタンをクリックすると、入力された名前と住所をPOSTリクエストで送信する。
- POST送信された名前と住所のJSON文字列が、ボディに含まれてレスポンスが返ってくる。
- レスポンスされた名前と住所を画面に表示する。
サンプルを構成するファイル
以下、上記サンプルを動作させているファイルの一覧と、ファイルの内容です。
ファイル一覧
- backbone-save-test.html
- 名前と住所を送信する画面
- backbone_save_test.js
- 名前と住所の値をModelに保持して、save(POSTリクエスト)するJavaScript
- backbone_save_test.php
- POSTリクエスト先のPHPファイル
backbone-save-test.htmlの一部
名前と住所の入力部分と、レスポンスデータを表示するテンプレート部分です。
<table class="table table-bordered">
<thead>
</thead>
<tbody>
<tr>
<th>名前</th>
<td><input type="text" id="user_name"></td>
</tr>
<tr>
<th>住所</th>
<td><input type="text" id="address"></td>
</tr>
</tbody>
</table>
<input type="button" id="btn_send" value="送信">
<br><br>
<!-- テンプレート(post_data_template)を表示する領域 -->
<div id="post_data_area"></div>
<!-- /テンプレート(post_data_template)を表示する領域 -->
<!-- レスポンスを受け取って表示するテンプレート -->
<script type="text/template" id="post_data_template">
<table class="table table-bordered">
<caption>POSTされたデータ</caption>
<thead>
<tr><th>名前</th><th>住所</th></tr>
</thead>
<tbody>
<tr>
<td><%= user_name %></td>
<td><%= address %></td>
</tr>
</tbody>
</table>
</script>
<!-- /レスポンスを受け取って表示するテンプレート -->
backbone_save_test.js
名前と住所の値をModelに保持して、save(POSTリクエスト)します。
$(function() {
var User = Backbone.Model.extend({
// ModelのリソースURI(本サンプルでは、Model.save()によるPOSTリクエスト先)
urlRoot : './backbone_save_test.php',
defaults : function() {
return {
'user_name' : null,
'address' : null
};
}
});
var BtnSend = Backbone.View.extend({
el : $('#btn_send'),
model : User,
initialize : function(options) {
this.model = options.model;
},
events: {
'click' : 'click'
},
click : function(e) {
var reqData = {
'user_name' : $('#user_name').val(),
'address' : $('#address').val()
};
// 送信するデータをModelにセット
this.model.set(reqData);
// save()を呼び出すと、model.urlRootにPOSTリクエストが送信される
this.model.save(null, {
success : function(model, resp) {
// レスポンスを受け取ってalert表示する
alert('名前:'+resp.user_name+' 住所:'+resp.address+' を受け付けました。');
// レスポンスを受け取ってテンプレートに表示する
$('#post_data_area').html(_.template($('#post_data_template').html(), resp));
},
error : function(model, resp) {
alert('エラー:送信に失敗しました。');
return false;
}
});
}
});
var user = new User();
var btnSend = new BtnSend({model: user});
});
backbone_save_test.php(修正前)
Model.save()により送信されたPOSTデータを、$_POSTから取得しようとしています。
<?php
$reqData = $_POST;
$respBody = array('user_name' => $reqData['user_name'], 'address' => $reqData['address']);
echo json_encode($respBody);
// end of file
$_POSTでは、application/jsonのPOSTデータを取得できない
Backbone.jsのsave()によるPOSTデータをPHPで取得する際に、少し困ったことがありました。
リクエストをPHPで受け付けた場合、$_POST($_REQUEST)などのスーパーグローバルを使ってリクエストデータを取得すると思いますが、$_POSTにはリクエストデータが入っていないのです。
Backbone.jsはPOSTリクエストボディにJSON文字列をそのまま入れて送信するため、
$_POSTが想定している形式と違うということのようです。
Backbone.jsとPHPが扱うContent-Typeの違い
- Backbone.js のPOSTリクエスト
- Content-Type: application/json
- PHPが想定しているPOSTリクエスト
- Content-Type: application/x-www-form-urlencoded
PHPでBackbone.jsのPOSTデータを取得する方法
方法は二つあります。
- “php://input”からリクエストボディを直接読み込む
- Backbone.emulateJSON = true に設定する
php:// — さまざまな入出力ストリームへのアクセス
php://input は読み込み専用のストリームで、 リクエストの body 部から生のデータを読み込むことができます。 POST リクエストの場合は $HTTP_RAW_POST_DATA よりも php://input を使うのが望ましいでしょう。php.ini ディレクティブの設定に依存しないからです。 さらに、$HTTP_RAW_POST_DATA がデフォルトで設定されない場合は、 always_populate_raw_post_data を有効にするよりも $HTTP_RAW_POST_DATA を使うほうがメモリの消費量が少なくなるでしょう。 php://input は、 enctype=”multipart/form-data” に対しては使用できません。
emulateJSON
If you’re working with a legacy web server that can’t handle requests encoded asapplication/json, setting Backbone.emulateJSON = true; will cause the JSON to be serialized under a model parameter, and the request to be made with aapplication/x-www-form-urlencoded mime type, as if from an HTML form.
上記の通り、Backbone.emulateJSONをtrueに設定する方法だと、Content-Type:application/x-www-form-urlencoded でPOSTリクエストが送信されるようになりますが、
今回は”php://input”を使う方法で対応します。
emulateJSONの説明文中の”a legacy web server”の部分が気に入らないというのもあって(レガシーとかじゃないだろとw)
backbone_save_test.php(修正後)
backbone_save_test.phpの内容を、以下のように修正します。
<?php
$reqData = json_decode(file_get_contents('php://input'), TRUE);
$respBody = array('user_name' => $reqData['user_name'], 'address' => $reqData['address']);
echo json_encode($respBody);
// end of file
修正後のサンプル
修正後のサンプルが、冒頭にも紹介したこちらです。(冒頭と同じ内容です)
Backbone.js saveサンプル


最近のコメント