カテゴリー
Linux

AngularJS を使って PHP へ JSON データを POST する方法

追記。「ログインページを介さず Basic 認証」シリーズの投稿一覧です♪

  1. 【Nginx】Basic 認証をかける方法手順メモ | oki2a24
  2. cURL を使って Basic 認証が必要な PHP へ JSON データを POST する手順メモ | oki2a24
  3. AngularJS を使って PHP へ JSON データを POST する方法 | oki2a24
  4. AngularJS を使って Basic 認証が必要な PHP へ JSON データを POST できません>< | oki2a24
  5. AngularJS を使って Basic 認証が必要な PHP へ JSON データを POST するサンプルコード! | oki2a24

追記終わり!

AngularJS を使用してウェブブラウザのページでボタンを押すと、サーバへ JSON データを POST して PHP で受け取ってファイルに出力したい。

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 してみたいですの。

うまくいくかしら?楽しみですわ♪

以上です。

コメントを残す