on 2015-01-12

AJAX - REST

REST 當道的現在, 不得不了解一下如何實作 CRUD(create, read, update, delete) 本文 server side 以 php 為例子

var xhr = new XMLHttpRequest();

xhr.open('GET', 'example.html', true);
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        document.getElementById('myDiv').innerHTML = xhr.responseText;
    }
};
xhr.send();

上面為一個簡單的 AJAX 行為

在此之前須了解在做 AJAX 行為時, 資料是如何跟 request 一起帶到 server side 大致上有 3 種

  • FormData
  • application/x-www-form-urlencoded
  • payload

前面 2 種是用傳統的 form 包起來一起帶到 server side 再經由 php 解析 GET / POST 由於 php 只有 $_GET & $POST 這無法達到真正的 rest(不過有人硬幹出來 tronice/epv) 所以必須由其他方式實作 最簡單的實作就是使用 $_SERVER['REQUEST_METHOD'] 來捕捉 4 種 request 的 method

$method = $_SERVER['REQUEST_METHOD'];
print_r($method);
switch($method)
{
    case "PUT":
        // do somethong
    break;
    case "GET":
        // do somethong
    break;
    case "DELETE":
        // do somethong
    break;
    case "POST":
        // do somethong
    break;
}

這是最簡單實作 rest 的方式 目前 php framework 大部份都有實作 rest, 所以也不用擔心加重開發上的負擔

FormData or application/x-www-form-urlencoded or payload?

接下來介紹一下這 3 種方式在前後端的行為差異 相信大家都了解 form 表單 submit 那在 AJAX 崛起之後把 Content-Type 設定成 application/x-www-form-urlencoded 是一個普遍的做法 jQuery 也是採用這方式實作的

setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’)

var obj = {
        'user': 'ted',
        'password': '123456'
    },
    jsonData;
jsonData = JSON.stringify(obj);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'test.php', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        document.getElementById('myDiv').innerHTML = xhr.responseText;
    }
};
xhr.send('json=' + jsonData);

FormData

之後出現 FormData 這個物件, 它的優勢在於使用比 application/x-www-form-urlencoded 的方式簡單而且 Content-Typemultipart/form-databoundary 的方式傳送 這有一個好處就是可以實作 AJAX 的 file upload, 而不是傳統的 form 表單檔案上傳 至於 AJAX 上傳的好處就是可以捕捉上傳進度、取消上傳, 做多檔上傳的排程(目前常見的 cloud storage service 幾乎都是這樣做)

var formData = new FormData();
formData.append('str', 'string');
formData.append('num', 123);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'test.php');
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        document.getElementById('myDiv').innerHTML = xhr.responseText;
    }
};
xhr.send(formData);

以上兩種方式在 PHP 中皆是以 $_GET or $_POST 接下來處理

if (isset($_POST['json']))
{
    echo $_POST['json'];
}
if (isset($_POST['str']))
{
    echo $_POST['str'];
}
if (isset($_POST['num']))
{
    echo $_POST['num'];
}

payload

這方法是個高端的方法, 第一次遇到這方法是在 AngularJS 上, 不過貌似國外開始漸漸這樣做了 這有方式個好處, 就是接收端不須經由 $_POST or $_GET 進來, 直接用 file_get_contents("php://input") 接收 client 端的 data 還有效能上的優勢, 因為不經由 $_POST or $_GET 進來可以減少成本增進效能 在 AngularJS 中會把 Content-Type 指定為 application/json 方便 server side 識別與處理

var obj = {
        'user': 'ted',
        'password': '123456'
    },
    jsonData;
jsonData = JSON.stringify(obj);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'test.php', true);
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        document.getElementById('myDiv').innerHTML = xhr.responseText;
    }
};
xhr.send('json=' + jsonData);

在 PHP 必須用 file_get_contents("php://input") 來接資料

$request = file_get_contents("php://input");
var_dump($request);
$data = json_decode($request);
echo '<br>';
echo 'data:';
echo '<br>';
echo 'User:' . $data->user;
echo '<br>';
echo 'Pwd:' . $data->password;

Finally

關於使用 FormData 與 payload 處理 file upload 之後會有文章補充