在服务端的WebService在被调用时,往往需要记录访问者IP、对IP进行限制或者其进行其他一些记录日志的操作,这时候需要我们对已经写好的接口增加拦截器。
编写拦截器
cxf有2种拦截器,InInterceptor、OutInterceptor,顾名思义,InInterceptor可以处理soap请求消息,OutInterceptor可以处理soap响应消息。所有的拦截器都继承自AbstractPhaseInterceptor<?>,此抽象拦截器实现了Interceptor接口。
我们写的拦截器如下:
package cn.com.dhcc.app.pub.core.interceptor;
import javax.servlet.http.HttpServletRequest;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.springframework.stereotype.Component;
import cn.com.dhcc.app.core.util.NetUtil;
@Component
public class InLoggingInterceptor extends AbstractPhaseInterceptor<Message> {
public InLoggingInterceptor() {
//指定拦截器在哪个阶段被激发,如果在调用之前进行拦截可使用PRE_INVOKE
//super(Phase.RECEIVE);
//获取函数名需要在这个阶段拦截,在RECEIVE获取可能是空值,因在RECEIVE阶段下,访问http://localhost:8061/dhcc-uums/ws/uums?wsdl时会被拦截,会获取到空值。
super(Phase.USER_LOGICAL);
}
@Override
public void handleMessage(Message message) throws Fault {
HttpServletRequest request = (HttpServletRequest) message.get(AbstractHTTPDestination.HTTP_REQUEST);
System.out.println("----IP------");
System.out.println(NetUtil.getRemoteIp(request));
Exchange exchange = message.getExchange();
OperationInfo ori = exchange.get(OperationInfo.class);
System.out.println("----方法名------");
System.out.println(ori.getInputName());
}
}
拦截器分为不同的Phase,各个Phase又有自己的拦截器链,参考http://cxf.apache.org/docs/interceptors.html。
代码中NetUtil.getRemoteIp这个函数是我们项目中用来获取IP地址的,代码如下:
public static String getRemoteIp(HttpServletRequest request){
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
if(request==null)return null;
String ip = request.getHeader("X-Forwarded-For"); //通过负载均衡获取真实客户端IP
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr(); //非负载均衡下直接获取
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = (String) ips[index];
if (!("unknown".equalsIgnoreCase(strIp))) {
ip = strIp;
break;
}
}
}
return ip;
}
修改配置文件
在完成接口,还没有配置拦截器前,对应的XML文件如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<jaxws:endpoint id="uumsServiceImplWs" implementor="#uumsServiceImpl" address="/uums" >
</jaxws:endpoint>
</beans>
这时候我们只需要在配置文件中WebService相关便签中增加拦截器:
<jaxws:inInterceptors>
<bean class="拦截器的实现类"/>
</jaxws:inInterceptors>
最后XML文件为:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
<jaxws:endpoint id="uumsServiceImplWs" implementor="#uumsServiceImpl" address="/uums" >
<jaxws:inInterceptors>
<bean class="cn.com.dhcc.app.pub.core.interceptor.InLoggingInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
此时在接口被访问时(例如访问http://localhost:8080/项目名称/ws/uums?wsdl
),就会输出客户端的IP地址。