前端发送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))//原地址校验
{      
		
	//这里可以直接返回,无需继续往下执行	
}

结语

以上是我在工作中对发送请求的一些认识,不足之后还请各位朋友指出,有不懂的地方或者更好的建议的可以给我留言,让我们一起共同进步。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值