Cross Domain with JSONP e

เคยไหมกับปัญหาการใช้ Api ข้าม Domain แล้วจะพบว่าไม่สามารถใช้งานได้ เนื่องจาก browser ตรวจสอบแล้วพบว่า ส่วนร้องขอข้อมูลกับส่วนประมวลผลข้อมูลเป็นคนละ domain กัน ดูจากรูปด้านล่าง http://location:81/test/json.html ไปยัง Api ที่อยู่ บน http://localhost:8080/testApi.php จะไม่สามารถแสดงผลได้ เนื่องจากการ Cross domain นั่นเอง

แล้วจะทำอย่างไรถึงจะใช้งานได้ล่ะ ? JSONP เป็นอีกหนึ่งทางเลือก ของการแก้ปัญหานี้ วิธีการนั้นทำได้โดย

  1. โดนรูปแบบของการส่งข้อมูล แทนที่จะเป็น json ธรรมดาก็เปลี่ยนเป็น json พร้อมกับ callback function สามารถทำได้โดยการเพิ่ม option dataType เป็น JSONP และ jsonpCallback ตามด้วยฟังก์ชั่น ที่เราเตรียมไว้ กับ ข้อมูล
  2. ส่ง callback query เพื่อให้ api บน server ทราบชื่อ callback function ที่เราเตรียมไว้ โดยรูปแบบของ json กับ jsonp จะแตกต่างกัน ตามรูปที่แสดง

Code ตัวอย่างด้านล่างนี้นะครับ

json.html :

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>JQuery (cross-domain) JSONP Twitter example</title>
        <script type="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
        <script>
            $(document).ready(function(){
              
        $('document').ready(function() {
            
          function photos (data) { 
            console.log(data);
          };
      
          var pm_url = 'http://localhost:8080/testApi.php?callback=photos'; 
          $.ajax({
            url: pm_url,
            //type: 'GET',
            success: function(json) {
              $("#data").text(JSON.stringify(json));
              console.dir(JSON.stringify(json));
            },
            error: function(e) {
              $("#data").text(e.message);
               console.log(e.message);
            },
            dataType: 'JSONP',
            jsonpCallback: 'photos',
            //jsonp: 'callback', 
          });
        });
            });
       
      //angular
      var app = angular.module('MyApp', []);
      app.controller('MyCtrl', function($scope, $http) {
        $scope.firstName = "John";
        $scope.lastName = "Doe";
        $scope.colorwheelies = "wait";
        
        $http.jsonp('http://localhost:8080/testApi.php?callback=angular.callbacks._0')
         .success(function(data){
          console.log(data);
          $scope.colorwheelies = data;
          //console.log(data);
          });
          
        $scope.search = function() {
           
        };
      }); 
        </script>
    </head>
    <body  ng-app="MyApp">
        
      Ajax Result :	<span id="data"></span><br/>
     
      <div ng-controller="MyCtrl">
       <p>
        Angularjs result : {{colorwheelies}}
       </p>
      </div> 
    </body>
</html>

testApi.php:

<?php
  
  $callback_fn = isset($_GET['callback'])?$_GET['callback']: 'angular.callbacks._0';
   
  $arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
  $result['result'] = $arr;
  
  if(false){
    echo  $callback_fn. "(".json_encode($result).")" ; //for angularjs as default;
    //angular.callbacks._0 ({"result":{"a":1,"b":2,"c":3,"d":4,"e":5}});
  }else{
    echo  json_encode($result) ;
    //{"result":{"a":1,"b":2,"c":3,"d":4,"e":5}};
  }
?>

 

Angularjs with Post method

วันนี้ ลองทดสอบ ใช้ Angularjs ส่งผ่าน method POST ไปที่ไฟล์ php บน server ของเรา ปรากฏว่า ไม่มีดาต้าจาก method POST ซะงั้น !!

ทำไม print_r($_POST) ถึงไม่มีข้อมูลอะไรอออกมาเลย แต่กลับมีข้อมูลใน $HTTP_RAW_POST_DATA  แทน ที่เป็นเช่นนี้เพราะอะไร ??

ลองดูตัวอย่าง code นี้จะเห็นได้ว่า Angularjs มีการส่งข้อมูลไปที่ server ด้วย method post แต่ข้อมูลที่ส่งจะมีลักษณะแตกต่างกันไป ตาม headers และการ encrypt data ด้วย หากต้องการให้ $_POST สามารถดักจับข้อมูลได้ ก็ต้อง แก้ไข header เป็น headers: { ‘Content-Type’: ‘application/x-www-form-urlencoded’} และ encrypt ฟังก์ชั่นด้วย   $httpParamSerializerJQLike สามารถดูรายละเอียดสามารถดูได้จาก  https://docs.angularjs.org/api/ng/service/$httpParamSerializerJQLike

index.php

 

<div ng-app="myApp" ng-controller="myCtrl">
  post_id : <input value="test" name="test"  ng-model="createModel.post_id" /> 
  post_name: <input value="test2222" name="test3342" ng-model="createModel.post_name" /><input type="button" ng-click="saveData()" name="senddata" value="senddata"> 
  
  <div><p> post : {{ response.post }}</p></div> 
  <div><p> post_raw_data : {{ response.post_raw_data }}</p></div> 
  <div><p> send_data : {{ response.send_data }}</p></div> 
  
</div>

<script src="angular.js"></script>
<script type="text/javascript">
  
   
    var app = angular.module('myApp', []);
    app.controller('myCtrl', function($scope, $http, $httpParamSerializerJQLike) {
        
        $scope.bCreate = false;
        $scope.bSearch = false;
        $scope.bResultTable = true;
        $scope.createModel = { 	post_id:'1', post_name:"test" };
        $scope.response = {post:'', post_raw_data:"", send_data:"" } 
        
        $scope.saveData = function() {
        //alert('saveData');
            $scope.bCreate = false;
        	$scope.bSearch = false;
        	$scope.bResultTable = true;
        	
        	console.log( $scope.createModel );
        	
        	$http({
              url: "addPostName.php",
              method: "POST",
          data: $httpParamSerializerJQLike($scope.createModel), //comment1
          //data: $scope.createModel,
          //data:   JSON.stringify($scope.createModel),  
          //headers: { 'Content-Type': 'application/x-www-form-urlencoded'} //comment1
          //headers: { 'Content-Type': 'application/json' }
          })
          .then(function(response) {
          $scope.response.post = response.data.POST;
          $scope.response.post_raw_data = response.data.HTTP_RAW_POST_DATA;
          $scope.response.send_data = response.data.DATA;
          	console.log(response);
                  // success
          }, 
          function(response) { // optional
          	console.log(response);
                  // failed
          });
        } 
    });  

</script>

addPostname.php

<?php  
    $result['POST'] =  isset($_POST['post_id'])?$_POST['post_id']: "POST is null  ";
     
    $result['HTTP_RAW_POST_DATA'] =  isset($HTTP_RAW_POST_DATA)?$HTTP_RAW_POST_DATA  : " POST_DATA  is  null  ";
     
    
    //echo " param " . $.param;
    
    if (isset($HTTP_RAW_POST_DATA  ))
      $result['DATA']  =  $HTTP_RAW_POST_DATA ;// $this->input->post('message');	 
    else
      $result['DATA']   = $_POST;
    
      echo json_encode( $result );

?>

รูปนี้ แสดงให้เห็นว่าถ้าเปลี่ยน headers type ดาต้าก็ที่ส่งขึ้น server ก็จะเปลี่ยนตามไปด้วย