追記。「ログインページを介さず Basic 認証」シリーズの投稿一覧です♪
- 【Nginx】Basic 認証をかける方法手順メモ | oki2a24
- cURL を使って Basic 認証が必要な PHP へ JSON データを POST する手順メモ | oki2a24
- AngularJS を使って PHP へ JSON データを POST する方法 | oki2a24
- AngularJS を使って Basic 認証が必要な PHP へ JSON データを POST できません>< | oki2a24
- AngularJS を使って Basic 認証が必要な PHP へ JSON データを POST するサンプルコード! | oki2a24
追記終わり!
AngularJS を使用してウェブブラウザのページでボタンを押すと、サーバへ JSON データを POST して PHP で受け取ってファイルに出力してみようと試みました!
苦労しましたので、記録を残しますわ♪
ポイント
- AngularJS で サーバに JSON をポストしたところエラーとなった。
- フロント側では、Access-Control-Allow-Origin のエラーが発生していた。
- サーバ側では method が POST ではなく、OPTIONS となっていた。
- クロスドメイン問題が原因だった。
- ちなみに、異なるドメインのデータにアクセスすることを、クロスドメインという。
- フロント側、サーバ側の両方で対応する必要がある。
- フロント側では、config で $httpProvider の Content-Type で x-www-form-urlencoded を設定する。
- サーバ側では、header(‘Access-Control-Allow-Origin: *’); を設定してやる。
エラーが発生した AngularJS のコード抜粋
var httpApp = angular.module('httpApp',[]); httpApp.controller('SendController', ['$scope', '$http', function($scope, $http) { $scope.dog = { name: "Fido", dob: new Date(), legs: [1, 2, 3, 4] }; var url = "https://oki2a24.com/basictest/json.php", config = { timeout: 5000 }; $scope.send = function() { $http.post(url, $scope.dog, config). success(function(data, status) { $scope.data = data; $scope.status = status; }). error(function(data, status) { $scope.data = data || "Request failed"; $scope.status = status; }); } }]);
これでよいはずと思っておりましたけれども、この内容だけではエラーとなることがわかってきました。エラー内容と、解決方法を最終的なコードも含めて具体的に書いていきますの♪
エラー内容
フロント(AngularJS、HTML)側
XMLHttpRequest cannot load https://oki2a24.com/basictest/json.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
サーバ(Nginx、PHP)側
Nginx の access.log です。コマンド「tail -f /var/log/nginx/access.log | grep basictest」で拾うことができました。
999.158.2.78 - - [27/Jul/2015:22:59:10 +0900] "OPTIONS /basictest/json.php HTTP/1.1" 200 48 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36" "-" unix: - - [27/Jul/2015:22:59:10 +0900] "OPTIONS /basictest/json.php HTTP/1.0" 200 37 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36" "999.158.2.78"
method が POST ではなく、OPTIONS となっております。
修正1
を参考に、フロントの AngularJS 部分について、次のように config を追加いたしました。
httpApp.config(function($httpProvider) { $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;application/json;charset=utf-8'; });
サーバ側は修正しておりません。
修正1の結果
フロント(AngularJS、HTML)側では変わらず同じエラーがでておりました><。また、レスポンスも、次のように返却されませんでした。
Request failed 0
一方サーバ(Nginx、PHP)側では、POST として認識されるようになりました♪
999.158.2.78 - - [27/Jul/2015:23:13:50 +0900] "POST /basictest/json.php HTTP/1.1" 200 48 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36" "-" unix: - - [27/Jul/2015:23:13:50 +0900] "POST /basictest/json.php HTTP/1.0" 200 37 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36" "999.158.2.78"
PHP が JSON を受け取ることもできておりました!
# cat recieved_json.txt object(stdClass)#1 (3) { ["name"]=> string(4) "Fido" ["dob"]=> string(24) "2015-07-27T14:13:46.588Z" ["legs"]=> array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) } } #
もう少しですわね♪ガンバロ!
修正2
フロント側は修正せず、サーバ側の、PHP を修正いたしました。
コードの最初に次を追加しました。
header('Access-Control-Allow-Origin: *');
修正2の結果
フロント(AngularJS、HTML)側のエラーも出なくなりました!しかも、サーバからレスポンスも次のように正しく返って来ましたの♪
{"response":"OK"} 200
これで完璧ですわね♪
修正3。修正1は不要だった!?
と思い、
- 修正1を行う前の状態
- 修正2は行った状態
でどうなるか試してみました。
結果、すべての修正を始める前と同じ状態となってしまいました><。
つまりフロント側でエラーとなりレスポンスも帰ってこない、サーバ側でもウェブサーバのログを見ると method が POST ではなく OPTIONS で JSON の内容は NULL でしたの><。
以上のことから、修正1および修正2の両方が必要と結論づけられました。
最終的に成功したコード
フロント側の HTML ファイル
<!doctype html> <html ng-app="httpApp"> <head> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script> <script> var httpApp = angular.module('httpApp',[]); httpApp.config(function($httpProvider) { $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;application/json;charset=utf-8'; }); httpApp.controller('SendController', ['$scope', '$http', function($scope, $http) { $scope.dog = { name: "Fido", dob: new Date(), legs: [1, 2, 3, 4] }; var url = "https://oki2a24.com/basictest/json.php", config = { timeout: 5000 }; $scope.send = function() { $http.post(url, $scope.dog, config). success(function(data, status) { $scope.data = data; $scope.status = status; }). error(function(data, status) { $scope.data = data || "Request failed"; $scope.status = status; }); } }]); </script> </head> <body> <div ng-controller="SendController"> <h2>送信データ</h2> {{dog}} <ul> <li>{{dog.name}}</li> <li>{{dog.dob}}</li> <li>{{dog.legs}}</li> </ul> <h2>送信</h2> <button ng-click="send()">送信</button> <h2>結果</h2> <ul> <li>{{data}}</li> <li>{{status}}</li> </ul> </div> </body> </html>
サーバ側の PHP ファイル
<?php header('Access-Control-Allow-Origin: *'); $json_string = file_get_contents('php://input'); ob_start(); var_dump(json_decode($json_string)); $out = ob_get_contents(); ob_end_clean(); file_put_contents('recieved_json.txt', $out); // レスポンス header 関数無くてもレスポンスできたが、Volley だからなのかどうかは不明 header("HTTP/1.1 200 OK"); header("Status: 200"); header("Content-Type: application/json; charset=utf-8"); header('X-Content-Type-Options: nosniff'); $response = array('response' => 'OK'); echo json_encode($response);
おわりに
以前 cURL コマンドを使用してサーバへ JSON データを POST し、PHP で受け取ってファイルに出力する方法をまとめました。
今回は、cURL ではなく、AngularJS から POST してみたところ、ずいぶんと苦労してしまいました。
これから AngularJS を使って Basic 認証を通して JSON データを POST してみたいですの。
うまくいくかしら?楽しみですわ♪
以上です。