深刻理解ajax系列第二篇——請求方式

前面的話

  在上一篇中,概要地介紹了XHR對象的使用。本文將詳細介紹使用XHR對象發送請求的兩種方式——GET和POST。下面將以實例的形式來詳細說明javascript

 

GET

  GET是最多見的請求類型,最經常使用於向服務器查詢某些信息,它適用於當URL徹底指定請求資源,當請求對服務器沒有任何反作用以及當服務器的響應是可緩存的狀況下php

【數據發送】html

  使用GET方式發送請求時,數據被追加到open()方法中URL的末尾前端

  數據以問號開始,名和值之間用等號連接,名值對之間用和號(&)分隔。使用GET方式發送的數據經常被稱爲查詢字符串java

xhr.open("get","example.php?name1=value1&name2=value2",true)

【編碼】ajax

  因爲URL沒法識別特殊字符,因此若是數據中包含特殊字符(如中文),則須要使用encodeURIComponent()進行編碼數據庫

  [注意]encodeURIComponent()只是6種編解碼方法的一種,關於它們的詳細信息移步至此json

var url = 'test.php' +'?name='  + encodeURIComponent("小火柴");
xhr.open('get',url,true);

  上面的URL被編碼爲後端

test.php?name=%E5%B0%8F%E7%81%AB%E6%9F%B4

【編碼函數】數組

  下面這個函數能夠輔助向現有URL的末尾添加查詢字符串參數

function addURLParam(url,name,value){
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url +=encodeURIComponent(name) + "=" + encodeURIComponent(value);
    return url;
}

  這個addURLParam()函數接受三個參數:要添加參數的URL、參數的名稱和參數的值。這個函數首先檢查URL是否包含問號(以肯定是否已經有參數存在)。若是沒有,就添加一個問號;不然,就添加一個和號。而後,將參數名稱和值進行編碼,再添加到URL的末尾。最後返回添加參數以後的URL

var url = 'test.php';
url = addURLParam(url,'name','aaa');
url = addURLParam(url,'data','bbb');

xhr.open('get',url,true);

【緩存】  

  在GET請求中,爲了不緩存的影響,能夠向URL添加一個隨機數或時間戳

xhr.open('get',url+'&'+Number(new Date()),true);
xhr.open('get',url+'&'+Math.random(),true);

【封裝函數】

  下面把使用get方式發送ajax請求的操做封裝爲get()函數

function get(url,data,callback){
    //建立xhr對象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //異步接受響應
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //實際操做
                callback && callback(xhr.responseText);
            }
        }
    }
    for(var key in data){
        url += (url.indexOf("?") == -1 ? "?" : "&");
        //編碼特殊字符
        url += encodeURIComponent(key) + "=" + encodeURIComponent(data[key]);
    }
    //增長隨機數,防止緩存    
    xhr.open('get',url+'&'+Number(new Date()),true);
    //發送請求
    xhr.send();
}
//前端
<script>
get('form.php',{
    a:1,
    b:2,
    c:3
},function(data){
    //'a:1;b:2;c:3;'
    console.log(data);
})
//後端
<?php
foreach($_GET as $key => $value){
    if(!empty($value)){
        echo $key. ":" .$value .";";        
    }
}
?>    

 

POST

  使用頻率僅次於GET的是POST請求,一般用於服務器發送應該被保存的數據。"POST"方法經常使用於HTML表單。它在請求主體中包含額外數據且這些數據常存儲到服務器上的數據庫中。相同URL的重複POST請求從服務器獲得的響應可能不一樣,同時不該該緩存使用這個方法的請求

  POST請求應該把數據做爲請求的主體提交,而GET請求傳統上不是這樣。POST請求的主體能夠包含很是多的數據,並且格式不限。在open()方法第一個參數的位置傳入"post",就能夠初始化一個POST請求

xhr.open("post","example.php",true);

【設置請求頭】

  發送POST請求的第二步就是向send()方法中傳入某些數據。因爲XHR最初的設計主要是爲了處理XML,所以能夠在此傳入XML DOM文檔,傳入的文檔經序列化以後將做爲請求主體被提交到服務器。固然,也能夠在此傳入任何想發送到服務器的字符串

  默認狀況下,服務器對POST請求和提交Web表單的請求並不會一視同仁。所以,服務器端必須有程序來讀取發送過來的原始數據,並從中解析出有用的部分。不過,可使用XHR來模仿表單提交:首先將Content-Type頭部信息設置爲application/x-www-form-urlencoded,也就是表單提交時的內容類型

xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");

  若是不設置Content-Type,發送給服務器的數據就不會出如今$_POSR超級全局變量中。這時要訪問一樣的數據,須藉助$HTTP_RAW_POST_DATA

  若是對相同的頭調用屢次setReQuestHeader(),新值不會取代以前指定的值。相反,HTTP請求將包含這個頭的多個副本或這個頭將指定多個值

【發送主體】

  接下來要以適當的格式建立一個字符串,並使用send()方法發送

  POST數據的格式與查詢字符串格式相同,名和值之間用等號連接,名值對之間用和號(&)分隔,以下所示

xhr.send('name="abc"&num=123');

【編碼和緩存】

  因爲使用POST方式傳遞數據時,須要設置請求頭"content-type",這一步驟已經可以自動對特殊字符(如中文)進行編碼,因此就再也不須要使用encodeURIComponent()方法了

  POST請求主要用於數據提交,相同URL的重複POST請求從服務器獲得的響應可能不一樣,因此不該該緩存使用POST方法的請求

【性能】

  GET對所發送信息的數量有限制,通常在2000個字符。與GET請求相比,POST請求消耗的資源會更多一些。從性能角度來看,以發送相同的數據計,GET請求的速度最多可POST請求的兩倍

【封裝函數】

  下面把使用post方式發送ajax請求的操做封裝爲post()函數

function post(url,data,callback){
    //建立xhr對象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //異步接受響應
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //實際操做
                callback && callback(xhr.responseText);
            }
        }
    }
    var strData = '';
    for(var key in data){
        strData += '&' + key + "=" + data[key];
    }
    strData = strData.substring(1); 
    xhr.open('post',url,true);
    //設置請求頭
    xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
    //發送請求
    xhr.send(strData);    
}
//前端
<script>
post('form.php',{
    a:1,
    b:2,
    c:3
},function(data){
    //'a:1;b:2;c:3;'
    console.log(data);
})
</script>    
//後端
<?php
foreach($_POST as $key => $value){
    if(!empty($value)){
        echo $key. ":" .$value .";";        
    }
}
?>

 

函數封裝

  在get和post這兩個段落中,分別對get和post這兩種方式進行了函數封裝。下面對它們進行整合,封裝爲一個可選擇請求方式的ajax()函數,並儲存爲ajax.js文件

function ajax(obj){
    //method爲ajax提交的方式,默認爲'get'方法
    obj.method = obj.method || 'get';
    //建立xhr對象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //異步接受響應
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //callback爲回調函數,若是不設置則無回調
                obj.callback && obj.callback(xhr.responseText);
            }
        }
    }
    //建立數據字符串,用來保存要提交的數據
    var strData = '';
    if(obj.method == 'post'){
        for(var key in obj.data){
            strData += '&' + key + "=" + obj.data[key];
        }    
        //去掉多餘的'&'
        strData = strData.substring(1); 
        xhr.open('post',obj.url,true);
        //設置請求頭
        xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
        //發送請求
        xhr.send(strData);    
    }else{
        //若是是get方式,則對字符進行編成
        for(var key in obj.data){
            strData += '&' + encodeURIComponent(key) + "=" + encodeURIComponent(obj.data[key]);
        }    
        //去掉多餘的'&',並增長隨機數,防止緩存
        strData = strData.substring(1) + '&'+Number(new Date());   
        xhr.open('get',obj.url+'?'+strData,true);
        //發送請求
        xhr.send();    
    }
}
<select name="year" id="year">
    <option value="2016">2016</option>
    <option value="2017">2017</option>
    <option value="2018">2018</option>
</select>
<select name="month" id="month">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
</select>
<select name="day" id="day">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
</select>
<button id="btn">發送</button>
<span id="result"></span>
<script>
btn.onclick = function(){
    ajax({
        url:'form.php',
        data:{year:year.value,month:month.value,day:day.value},
        callback:function(data){
            result.innerHTML = data;
        }
    })    
}
</script>    
<?php
echo '你選擇的日期是' .$_GET['year'] .'年' .$_GET['month'] .'月'.$_GET['day'] .'日';
?>    

實例

  下面以一個實例來講明GET和POST兩種請求方式的應用

<!-- 前端頁面 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{font-size: 30px;margin: 0;line-height: 1.5;}
select,button,input{font-size: 30px;line-height: 1.5;}
</style>
</head>
<body>
<h2>員工查詢</h2>    
<label>請輸入員工編號:</label>
<input type="text" id="keyword">
<button id="search">查詢</button>
<p id="searchResult"></p>

<h2>員工建立</h2>
<form id="postForm">
    <label>請輸入員工姓名:</label>
    <input type="text" name="name"><br>
    <label>請輸入員工編號:</label>
    <input type="text" name="number"><br>
    <label>請輸入員工性別:</label>
    <select name="sex">
    <option value="男"></option>
    <option value="女"></option>
    </select><br>
    <label>請輸入員工職位:</label>
    <input type="text" name="job"><br>
    <button id="save" type="button">保存</button>    
</form>
<p id="createResult"></p>
<script>
/*get*/
//查詢
var oSearch = document.getElementById('search');
//get方式添加數據
function addURLParam(url,name,value){
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url +=encodeURIComponent(name) + "=" + encodeURIComponent(value);
    return url;
}
oSearch.onclick = function(){
    //建立xhr對象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //異步接受響應
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //實際操做
                document.getElementById('searchResult').innerHTML = xhr.responseText;
            }else{
                alert('發生錯誤:' + xhr.status);
            }
        }
    }
    //發送請求
    var url = 'service.php';
    url = addURLParam(url,'number',document.getElementById('keyword').value);
    xhr.open('get',url,true);
    xhr.send();
}

/*post*/
//建立
var oSave = document.getElementById('save');
//post方式添加數據
function serialize(form){        
    var parts = [],field = null,i,len,j,optLen,option,optValue;
    for (i=0, len=form.elements.length; i < len; i++){
        field = form.elements[i];
        switch(field.type){
            case "select-one":
            case "select-multiple":
                if (field.name.length){
                    for (j=0, optLen = field.options.length; j < optLen; j++){
                        option = field.options[j];
                        if (option.selected){
                            optValue = "";
                            if (option.hasAttribute){
                                optValue = (option.hasAttribute("value") ? option.value : option.text);
                            } else {
                                optValue = (option.attributes["value"].specified ? option.value : option.text);
                            }
                            parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(optValue));
                        }
                    }
                }
                break;              
            case undefined:     //fieldset
            case "file":        //file input
            case "submit":      //submit button
            case "reset":       //reset button
            case "button":      //custom button
                break;                
            case "radio":       //radio button
            case "checkbox":    //checkbox
                if (!field.checked){
                    break;
                }
                /* falls through */
            default:
                //don't include form fields without names
                if (field.name.length){
                    parts.push(encodeURIComponent(field.name) + "=" + encodeURIComponent(field.value));
                }
        }
    }        
    return parts.join("&");
}
oSave.onclick = function(){
    //建立xhr對象
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject('Microsoft.XMLHTTP');
    }
    //異步接受響應
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4){
            if(xhr.status == 200){
                //實際操做
                document.getElementById('createResult').innerHTML = xhr.responseText;
            }else{
                alert('發生錯誤:' + xhr.status);
            }
        }
    }
    //發送請求
    xhr.open('post','service.php',true);
    xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
    xhr.send(serialize(document.getElementById('postForm')));
}
</script>
</body>
</html>
<!-- 後端頁面 -->
<?php 

//用於過濾不安全的字符
function test_input($data) {
   $data = trim($data);
   $data = stripslashes($data);
   $data = htmlspecialchars($data);
   return $data;
}
//設置頁面內容的html編碼格式是utf-8,內容是純文本
header("Content-Type:text/plain;charset=utf-8");
//header("Content-Type:application/json;charset=utf-8");
//header("Content-Type:text/xml;charset=utf-8");
//header("Content-Type:text/html;charset=utf-8");
//header("Content-Type:application/javascript;charset=utf-8");
//定義一個多維數組,包含員工的信息,每條員工信息爲一個數組
$staff = array(
    array("name"=>"洪七","number"=>"101","sex"=>"男","job"=>'總經理'),
    array("name"=>"郭靖","number"=>"102","sex"=>"男","job"=>'開發工程師'),
    array("name"=>"黃蓉","number"=>"103","sex"=>"女","job"=>'產品經理')
    );

//判斷若是是get請求,則進行搜索;若是是POST請求,則進行新建
//$_SERVER["REQUEST_METHOD"]返回訪問頁面使用的請求方法
if($_SERVER["REQUEST_METHOD"] == "GET"){
    search();
}else if($_SERVER["REQUEST_METHOD"] == "POST"){
    create();
}

//經過員工編號搜索員工
function search(){
    //檢查是否有員工編號的參數
    //isset檢測變量是否設置;empty判斷值是否爲空
    if(!isset($_GET['number']) || empty($_GET['number'])){
        echo '參數錯誤';
        return;
    }
    global $staff;
    $number = test_input($_GET['number']);
    $result = '沒有找到員工';

    //遍歷$staff多維數組,查找key值爲number的員工是否存在。若是存在,則修改返回結果
    foreach($staff as $value){
        if($value['number'] == $number){
            $result = "找到員工:員工編號爲" .$value['number'] .",員工姓名爲" .$value['name'] .",員工性別爲" .$value['sex'] .",員工職位爲" .$value['job'];
            break;
        }
    }
    echo $result;
}

//建立員工
function create(){
    //判斷信息是否填寫徹底
    if(!isset($_POST['name']) || empty($_POST['name']) || 
       !isset($_POST['number']) || empty($_POST['number']) ||
       !isset($_POST['sex']) || empty($_POST['sex']) ||
       !isset($_POST['job']) || empty($_POST['job']) 
        ){
        echo "參數錯誤,員工信息填寫不全";
        return;
    }

    echo "員工" .test_input($_POST['name']) ."信息保存成功!";
}
?>
相關文章
相關標籤/搜索