AngularJS TIPS
サーバーサイドとHTTP POSTで非同期通信するには?($http)
AngularJSでHTTP POSTで非同期通信する方法を説明。また、送信データをJSONではなくjQuery形式にする方法や、PHPでJSONデータをデコードする方法も紹介する。
別稿「TIPS:サーバーサイドと非同期通信するには?」では、$http
サービスを利用してHTTP GETによる非同期通信を実装してみました。本稿では、引き続き$http
サービスを利用したHTTP POSTの方法を見てみます。前半ではHTTP POSTを利用した場合の問題点を確認した上で、後半では、その対処方法を解説します。
HTTP POSTを利用する場合の注意点
まずは、別稿のサンプルをHTTP POST対応に書き換えてみましょう(変更したのは太字部分)。テキストボックスに入力された名前に基づいて、「Hello, ●○!」のようなあいさつメッセージを返すことを想定しています。
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>AngularJS TIPS</title>
</head>
<body ng-controller="MyController">
<form name="myForm" novalidate>
<label for="name">名前:</label>
<input id="name" name="name" type="text" ng-model="name" />
<button ng-click="onclick()">送信</button>
</form>
<div>{{result}}</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script>
angular.module('myApp', [])
.controller('MyController', ['$scope', '$http', function($scope, $http) {
$scope.onclick = function() {
// 1サーバーに対してHTTP POSTでリクエストを送信
$http({
method: 'POST',
url: 'post.php',
data: { name: $scope.name }
})
// 成功時の処理(ページにあいさつメッセージを反映)
.success(function(data, status, headers, config){
$scope.result = data;
})
// 失敗時の処理(ページにエラーメッセージを反映)
.error(function(data, status, headers, config){
$scope.result = '通信失敗!';
});
};
}]);
</script>
</body>
</html>
|
<?php
// 2ポストデータnameを取得
$data = $_POST['name'];
if (empty($data)) {
header('HTTP/1.1 500 Internal Server Error');
} else {
print('Hello,'.$data.'!');
}
|
$http
サービスでHTTP POSTリクエストを送信するには、method
パラメーターにPOSTを指定した上で、入力値はdata
パラメーターに設定します(1)。HTTP GETではparams
パラメーターを利用していましたが、こちらはクエリ情報を表すものなので、注意してください。また、サーバーサイドではポストデータを受け取るために、スーパーグローバル変数$_GET
を$_POST
に置き換えています(2)。
これでうまくいきそうな気がしますが、結果はエラーとなります。
この原因は、開発者ツールでリクエストデータを確認すると明らかです。リクエストデータがJSON(JavaScript Object Notation)で送信されています。$_POST
は、標準で「application/x-www-form-urlencoded」形式のデータを受け取りますので、このままでは解釈できません。結果、$_POST['name']
は空となり、エラーが発生しています。
リクエストデータの形式を変換する
この問題を回避する一つ目の方法は、$http
サービスのデータ形式を変換することです。これには、リスト1を以下のように変更してみましょう。
angular.module('myApp', [])
.controller('MyController',
['$scope', '$http', '$httpParamSerializerJQLike',
function($scope, $http, $httpParamSerializerJQLike) {
$scope.onclick = function() {
$http({
method: 'POST',
headers: {
// 1リクエストヘッダーを設定
'Content-Type' : 'application/x-www-form-urlencoded;charset=utf-8'
},
// 2リクエストデータをjQueryと同様の形式で送信
transformRequest: $httpParamSerializerJQLike,
url: 'post.php',
data: { name: $scope.name }
})
.success(function(data, status, headers, config){
$scope.result = data;
})
.error(function(data, status, headers, config){
$scope.result = '!!通信に失敗しました!!';
});
};
}]);
|
headers
パラメーターには、リクエストヘッダーを設定します(1)。ここではContent-Type
ヘッダー(データ形式)を、一般的なフォームからの送信フォーマットである「application/x-www-form-urlencoded」で宣言しています。
ただし、これだけではデータ形式を宣言しているだけなので、データを実際に変換する必要があります。もっとも、これにはAngularJS 1.4*1から導入された$httpParamSerializerJQLike
を呼び出すだけです。$httpParamSerializerJQLike
は、リクエストデータをjQueryと同様の形式でシリアライズするためのサービスです。これをtransformRequest
(リクエスト変換関数)パラメーターに渡すことで(2)、リクエストがapplication/x-www-form-urlencoded形式に変換されます。
- *1 AngularJS 1.3以前では、独自の変換コードを
transformRequest
パラメーターに引き渡す必要があります。詳しくは、後日別稿で解説の予定です。
補足:サーバーサイドでJSONデータをデコードする
クライアントサイドのコードには手を入れず、サーバーサイドでJSON形式のデータを受け取るようにすることもできます。PHPの例ではありますが、他の言語を利用している場合にも、一つの参考としてください。
<?php
$data = json_decode(file_get_contents('php://input'), TRUE);
if (empty($data['name'])) {
header('HTTP/1.1 500 Internal Server Error');
} else {
print('Hello,'.$data['name'].'!');
}
|
※このコードを実行するには、HTMLソースはリスト1に戻して、JSON形式で送信するようにしておく必要がある。
「php://input」(標準入力)は、リクエスト本体を生データ(ここではJSON文字列)として受け取ります。ここでは、file_get_contents
関数でJSON文字列を読み込み、その結果をjson_decode
関数でデコード、連想配列に変換(=第2引数でTRUEを指定)しています。あとは、$data['name']
のような形式で、個々の入力項目にアクセスできます。
API:$http カテゴリ:ng(コアモジュール) > service(サービス)
※以下では、本稿の前後を合わせて5回分(第34回~第38回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
35. サーバーサイドと非同期通信するには?($http)
AngularJSでサーバーサイドのWeb APIと非同期通信する方法を説明。また、ログの種類や、ショートカットメソッドについても紹介する。
36. 【現在、表示中】≫ サーバーサイドとHTTP POSTで非同期通信するには?($http)
AngularJSでHTTP POSTで非同期通信する方法を説明。また、送信データをJSONではなくjQuery形式にする方法や、PHPでJSONデータをデコードする方法も紹介する。
37. JSON形式のWeb APIにアクセスするには?($http)
Web APIと通信する際に問題となるクロスドメイン制約を回避するために使われるテクニック「JSONP」を、AngularJSで実現するための基本的な方法を説明する。
38. 指定された時間の経過で処理を実行するには?($interval/$timeout)
ミリ秒単位で処理を実行できる、いわゆる「タイマー」である$intervalサービスの基本的な使い方を解説。また、一定時間後に処理を実行する$timeoutサービスについても説明する。