前端發送ajax請求以及源地址校驗(java + JavaScript)

前言

前端js發送ajax請求來獲取數據是很常見的一種方式,通過這段時間的工作,我對這個發送請求的js進行了封裝,使用起來更加方便,還有可能涉及到的一些安全知識,接下來我就給各位朋友分享一下。

正文

1、ajax請求的封裝

下面這個是我對發送ajax請求進行了封裝,好用又實在。

var remindAjax={
     jsonpCall:function(url,param,beforesendfn,successfn,errorfn){
         $.ajax({
             type: "POST",                     
             async: true,
             dataType: "jsonp",
             jsonp: "jsonpCallBack",
             url: url,
             data: param,
             jsonpCallback:"callBackHandler" ,
             beforeSend: function(){    
                 beforesendfn();                        
             },
             success: function (data) {
                 successfn(data);
             },
             error:function(data){
                 errorfn(data);
             }

         });            
    },
    ajaxPost:function(url,param,beforesendfn,successfn,errorfn){
         $.ajax({
            type: "POST",                      
            async: true,
            dataType: "json",
            url: url,
            data: param,
            beforeSend: function(){ 
                beforesendfn();                     
            },
            success: function (data) {
                successfn(data);
            },
            error:function(data){
                errorfn(data);
            }

         });            
    }
}

以前我發送異步請求的時候,一般使用下面這種寫法,但是後來在工作中遇到這個封裝的函數,將發請求部分提取了出來,減少了冗餘的代碼。

$.ajax({
            type: "POST",                      
            async: true,
            dataType: "json",
            url: url,
            data: param,
            success: function (data) {
                successfn(data);
            }

         });    

如果你想調用這個函數的時候,可以參照下面的寫法:

var param = new Object();
            param.operate=operate;
            remindAjax.ajaxPost(basedata.Uri.GetAjaxHandler() +"/insertUserClick.html",param,
                        function(){
                                console.log(operate);
                        },           
                        function (data) {
                            if (data == null) return;
                        },
                        function(data)
                        {
                            alert("服務器錯誤,請嘗試");     

                        }
             ); 

其實,上面的代碼。你還可以繼續封裝成一個函數,不過就是參數和請求地址,結果處理都固定了下來,如果使用頻率高的話可以考慮

function insertLog(operate){
    var param = new Object();
    param.operate=operate;
    remindAjax.ajaxPost(basedata.Uri.GetAjaxHandler() +"/insertUserClick.html",param,
        function(){
                console.log(operate);
            }, 
       function (data) {
                if (data == null) return;
                    },
            function(data)
                    {
            alert("服務器錯誤,請嘗試");
                    }
}

調用的時候傳入參數即可,比如:insertLog(‘fristLoad’);
請求地址url部分還可以在繼續寫成函數basedata.Uri.GetAjaxHandler()

var basedata={
        Uri: {          
            GetAjaxHandler: function() {
                return window.location.href.split('?')[0].substring(0, window.location.href.split('?')[0].lastIndexOf('/'));
            }
        },   
        getQueryString: function()
        {
                 var reg = new RegExp("(^|&)SP=([^&]*)(&|$)");
                 var r = window.location.search.substr(1).match(reg);
                 if(r!=null)return  unescape(r[2]); return '';
        },
        closeTab:function(){
                var userAgent = navigator.userAgent;
                if (userAgent.indexOf("Firefox") != -1 || userAgent.indexOf("Chrome") != -1) {
                    window.location.href = "about:blank";
                    window.top.opener = null;
                    window.close();
                } else {
                    window.opener = null;
                    window.open("", "_self");
                    window.close();
                }
        }   

}

Uri 這個函數是用來獲取當前請求地址的,也就是說,如果地址的前綴都一樣,那麼使用
basedata.Uri.GetAjaxHandler() +"/insertUserClick.html 這個寫法就可以鏈接到你想到的地址,而不用每次都寫絕對地址,例如:http://192.168.168.213:8008/hyhb_pt/remind/hy0222/ + 你的controller地址,比如insert.do 拓展性會好一點。getQueryString是用來截取參數的,這裏是截取‘’sp=‘’後面的參數。closeTab 這個是用來關閉當前瀏覽器頁面的,不過的瀏覽器效果也許不大一樣。

2、後臺接收參數

比如說,如果你是下面的這種寫法

var param = new Object();
param.operate=operate;

那麼接收參數的時候可以寫成這樣

String operate = (String)request.getParameter("operate")

3、發送請求前的操作

如果是點擊事件,通過簡單的js校驗,然後發送請求,那麼在點擊之後,服務端返回數據之前,應該將這個按鈕鎖定起來,讓它不可點擊。我常遇到的有兩種,第一種就是input 標籤 ,如果你是這種寫法的

function click() {
  $('.btn').on('click', function() {   

    //校驗通過 解綁按鈕
    $('.btn').unbind('click');
   ........

    //請求完成,繼續綁定。    
  // click();           
});
}

第二種就是圖片標籤,比如說下面代碼,一般是通過給標籤一個id,然後綁定點擊事件,這個時候,我的建議是加遮罩層,也就是點擊之後給圖片加上遮罩層,讓她無法點擊,請求完成之後去掉遮罩層。

<img class="btn" src="../resources/style/time/images/rightNow.png" alt="" id="push_click">

通過以上兩種方式的使用,可以避免由於網絡延遲導致用戶在返回前多次點擊按鈕,發送多次請求,消耗服務器的資源,有時候會導致一些重複的數據(單身多年,手速夠快是可以實現在返回前多次點擊的)。所以說,鎖定按鈕的方式還是很有必要的。

4、涉及到的服務端安全問題,源地址校驗

其實這裏涉及到一個安全問題,就是java代碼也可以實現發出post和get的請求。一般來說我們默認從客戶端發送的請求是正常請求,但是如果這個數據包被別人攔截,解析你的url和參數,然後用其它語言(比如java)來給這個請求地址發送他自己捏造的參數(參數名字和順序一樣,參數值不一樣),也可以正常的請求到我們的數據,這就存在一定的安全隱患。

所以我的建議是在java代碼中添加源地址校驗,爲什麼可以這麼做呢?從客戶端發出的ajax 請求和自己寫java代碼實現的請求,有一個區別就是請求頭的不一樣,比如說你部署應用的服務器ip是192.168.5.125,那麼客戶端發送請求到你的服務器,帶過來的地址就是192.168.5.125;不過你要是部署在本地(比如你的ip爲192.1.1.14),比如說部署到自己的tomcat服務器,那麼用代碼實現發請求,那麼帶過去的請求頭就會出現192.1.1.14這個地址,這就是客戶端發請求和自己寫java代碼發請求很明顯的一個區別。所以我們可以通過這個區別來做文章。

請看下面這個工具類的代碼:

public class Tools {

public static boolean ValidReferer(HttpServletRequest request) {
        String referer = request.getHeader("referer");
        Log.debug("referer="+referer);
        if (referer == null)
            return false;
        List<String> host = ReadAllowIPXml();
        if (host != null && host.size() > 0) {
            for (int i = 0; i < host.size(); i++) {
                if (referer.startsWith("http://" + host.get(i)))
                    return true;
            }
        }
        return false;
    }

    private static List<String> ReadAllowIPXml() {
        List<String> strs = null;
        try {
            File f = new File(Tools.class.getClassLoader().getResource("conf/allowIP.xml").getPath());
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(f);
            NodeList nl = doc.getElementsByTagName("ip");
            if (nl != null && nl.getLength() > 0)
                strs = new ArrayList<String>();
            for (int i = 0; i < nl.getLength(); i++) {
                strs.add(nl.item(i).getFirstChild().getNodeValue());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return strs;
    }

}

每次控制器接收到ajax請求的時候,就去讀取allowIP.xml配置文件,然後看看是否存在列表中,如果在的話,就視爲正常請求。

這個是allowIP.xml裏面的寫法,裏面就是你允許訪問你得控制器的服務器地址,,我在實踐的時候這裏覺得這裏應該有兩種寫法,主要是看你的請求地址,如果是http://192.168.4.242:8080/edu/remindpage.do這種,那麼你應該配置ip地址,如果是https://www.baidu.com/這種,你就可以配置域名,其實這個還是受限於前面的工具類代碼,如果你有興趣的話,可以改寫成更好的代碼(這樣配置文件只需要寫ip地址或者域名即可)。

<?xml version="1.0" encoding="UTF-8"?>
<ips>
<ip>192.168.4.242</ip>
<ip>www.baidu.com</ip>
</ips>

請求進入controller控制器,通過下面的代碼


if(!Tools.ValidReferer(request))//原地址校驗
{      

    //這裏可以直接返回,無需繼續往下執行 
}

結語

以上是我在工作中對發送請求的一些認識,不足之後還請各位朋友指出,有不懂的地方或者更好的建議的可以給我留言,讓我們一起共同進步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章