背景:预防高频访问 (在10秒内访问达到一定的次数转跳到防刷页面),10秒内访问超过1w次存入内存。项目用的strus2+memcache,java代码和配置如下
package com.woyaou.base.interceptor;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.woyaou.base.util.CommonCache;
import com.woyaou.base.util.ConfigReaderUtils;
import com.woyaou.base.util.DateUtil;
import com.woyaou.base.util.IpUtils;
import com.woyaou.base.util.LogUtils;
/**
* 异常拦截器
*@Description: 预防高频访问 (在10秒内访问达到一定的次数转跳到防刷页面)
*@author Wupeng
*@date 2013-09-11
*
*/
@SuppressWarnings("serial")
public class ChallengeCollapsarInterceptor extends AbstractInterceptor {
//对于高频访问者的阻塞时间
private static int BLOCK_CACHE_TIME = 60;
//对于访问计数缓存时间
private static int COUNT_CACHE_TIME = 10;
//10秒内访问访问限制次数
private static int BLACK_TIME_LIMIT = 1000000;
@Autowired
private CommonCache commonCache;
public String intercept(ActionInvocation invocation) throws Exception {
final HttpServletRequest request = ServletActionContext.getRequest();
String clientIp =IpUtils.getIpAddr(request);
String blackKey = "black-"+clientIp;
//检查用户是否在阻塞队列中。
String value = (String)commonCache.get(blackKey);
if(value != null){
return "blackpage";
}
String requestURI = request.getRequestURI();
String strTime = DateUtil.getTimeLong().substring(0,9); //10秒时间, 9位是10秒级。
String countKey = "count-"+strTime+"-"+clientIp+"-"+requestURI;
int iTimes = 0;
//取出10内的访问次数。
value = (String)commonCache.get(countKey);
if(value != null){
iTimes = Integer.valueOf(value)+1;
if(iTimes > BLACK_TIME_LIMIT){ //10秒内访问次数大于限定次数
commonCache.add(blackKey, BLOCK_CACHE_TIME, "1");//加入阻塞缓存
LogUtils.info("blacked:"+blackKey);
}
}
//加入计数队列
commonCache.set(countKey, COUNT_CACHE_TIME, String.valueOf(iTimes));
return invocation.invoke();
}
public void init(){
LogUtils.info("ChallengeCollapsarInterceptor:init()");
String limits = ConfigReaderUtils.getValue("black_refresh_limit");
if(limits != null){
BLACK_TIME_LIMIT = Integer.valueOf(limits).intValue();
}
}
public void destroy(){
LogUtils.info("ChallengeCollapsarInterceptor:destroy()");
}
}
struts.xml配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- action可访问 -->
<constant name="struts.action.extension" value="action"/>
<constant name="struts.devmode" value="true" />
<constant name="struts.i18n.encoding" value="UTF-8" />
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<!-- 公共配置 -->
<include file="struts-common.xml"></include>
<!-- 项目功能 -->
<include file="com/woyaou/base/action/struts-ajaxcommon.xml"></include>
<!-- 火车票-车站 -->
<include file="com/woyaou/train/action/station/struts-station.xml"></include>
<!-- 火车票-时刻 -->
<include file="com/woyaou/train/action/shike/struts-shike.xml"></include>
<!-- 火车票-预售期 -->
<include file="com/woyaou/train/action/presale/struts-presale.xml"></include>
</struts>
struts-common.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
"http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="common" namespace="/" extends="struts-default">
<interceptors>
<!--定义一个异常拦截器-->
<interceptor name="exception" class="com.woyaou.base.interceptor.ExceptionInterceptor" />
<interceptor name="challengeCollapsar" class="com.woyaou.base.interceptor.ChallengeCollapsarInterceptor" />
<!--定义一个包含权限检查的拦截器栈-->
<interceptor-stack name="mydefault">
<!--配置内建默认拦截器-->
<interceptor-ref name="defaultStack" />
<!--配置自定义的拦截器-->
<interceptor-ref name="exception" />
<interceptor-ref name="challengeCollapsar" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="mydefault" />
<default-action-ref name="dispatcheer" />
<!--定义全局Result-->
<global-results>
<result name="404">/404.html</result>
<result name="error">/otherError.html</result>
<result name="login" type="redirect">/index.jsp</result>
<result name="blackpage" type="redirect">/refreshBlack.html</result>
</global-results>
<action name="dispatcheer">
<result>/404.html</result>
</action>
<!-- train search -->
<action name="search" class="trainSearchAction">
<!-- search shike by statioin -->
<result name="shike_station" type="httpheader">
<param name="status">301</param>
<param name="headers.Location">${forwardDomain}/${fromStationPy}/</param>
</result>
<!-- search shike by statioin to station -->
<result name="shike_station2station" type="httpheader">
<param name="status">301</param>
<param name="headers.Location">${forwardDomain}/${fromStationPy}-${toStationPy}.html</param>
</result>
</action>
</package>
<package name="common_ajax" namespace="/" extends="json-default">
<interceptors>
<!--定义一个异常拦截器-->
<interceptor class="com.woyaou.base.interceptor.ExceptionInterceptor" name="exception" />
<interceptor name="challengeCollapsar" class="com.woyaou.base.interceptor.<span style="color:#ff0000;"><strong>ChallengeCollapsarInterceptor</strong></span>" />
<!--定义一个包含权限检查的拦截器栈-->
<interceptor-stack name="mydefault">
<!--配置内建默认拦截器-->
<interceptor-ref name="defaultStack" />
<!--配置自定义的拦截器-->
<interceptor-ref name="exception" />
<interceptor-ref name="challengeCollapsar" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="mydefault" />
<default-action-ref name="dispatcheer" />
<!--定义全局Result-->
<global-results>
<result name="404">/404.html</result>
<result name="error">/other.html</result>
<result name="login" type="redirect">/index.jsp</result>
<result name="blackpage" type="redirect">/refreshBlack.html</result>
</global-results>
<action name="dispatcheer">
<result>/404.html</result>
</action>
</package>
</struts>