1.过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
过滤器的顺序每一次都将chain对象传入,达到最后接口回调的效果:
一、实现原理不同
过滤器的实现基于回调函数拦截器基于Java的反射机制【动态代理】实现。
二、使用范围不同
过滤器是Servlet的规范,需要实现javax.servlet.Filter接口,Filter使用需要依赖于Tomcat等容器。拦截器是Spring组件,定义在org.springframework.web.servlet包下,由Spring容器管理【又有更加丰富的生缪那个周期处理方法,细粒度,且能够使用Spring中的资源】,不依赖Tomcat等容器。
2.拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
拦截器的顺序preHandle1 -> preHande2 -> 【Controller】 -> postHandle2 -> postHandle1 -> afterCompletion2 -> afterComplention1
preHandle按照注册顺序,后两个与注册顺序相反。
一个拦截器的preHandle为false,则之后的所有拦截器都不会执行。一个拦截器的preHandle为true,则这个拦截器的triggerAfterCompletion一定会执行。只有所有的拦截器preHandler都为true,也就是正常执行,postHandle才会执行。
简而言之:
- 相比于拦截器,过滤器更加底层,执行时机更靠前,有利于防渗透扫描
- 过滤器可以拦截静态资源,方便我们做一些权限控制
- 部分Web框架根本就没有提供拦截器功能,但几乎所有的Web框架都会提供过滤器机制
但是过滤器也有一些缺点,比如:
- 由于太过底层,导致无法率先拿到
HandlerMethod
对象,无法据此添加一些额外功能- 由于拦截的太全面了,导致我们需要对很多特殊路由(如
/favicon.ico
)做一些额外处理- 在Spring中,过滤器中抛出的异常无法进入全局
@ExceptionHandler
,我们必须额外编写代码进行异常处理
主要区别:
1、拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
2、拦截器不依赖于servlet容器,过滤器依赖于servlet容器。
3、拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4、拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5、在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
6、拦截器可以获取IOC容器中的各个bean(基于FactoryBean接口 ),而过滤器就不行,在拦截器里注入一个service,可以调用业务逻辑。
本质区别:
从灵活性上说拦截器功能更强大些,Filter能做的事情它都能做,而且可以在请求前,请求后执行,比较灵活。
Filter主要是针对URL地址做一个编码的事情、过滤掉没用的参数、安全校验,其他的还是建议用interceptor。
过滤器-----拦截前-----Action处理-----拦截后-----过滤后。
过滤器中获取流丢失问题解决
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
/**
* 单点登录Filter
*
* @author hbw
*/
@Slf4j
@Component
public class LoginFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String loginUrl = "http://server.smart-sso.com:8080/login?appId=demo1&redirectUri=http://demo.smart-sso.com:8082/";
log.info("前" + loginUrl);
// ServletRequest requestWrapper= new ContentCachingRequestWrapper((HttpServletRequest) request);
// 一个request的包装类,初始化时缓存了body,重写了getInputStream返回缓存的body,实现重复读取body
BodyCacheReaderRequestWrapper requestWrapper = new BodyCacheReaderRequestWrapper(httpRequest);
String requestURI = requestWrapper.getRequestURI();
System.out.println("--------------------->过滤器:请求地址" + requestURI);
String str = getBody(requestWrapper);
log.info(str);
// httpResponse.sendRedirect(loginUrl);
filterChain.doFilter(requestWrapper, httpResponse);
log.info("后" + loginUrl);
log.info(JsonHelper.toJson(httpRequest.getAttributeNames()));
}
@Override
public void destroy() {
Filter.super.destroy();
}
public String getBody(HttpServletRequest request) {
try {
ServletInputStream in = request.getInputStream();
String body;
body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
return body;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class BodyCacheReaderRequestWrapper extends HttpServletRequestWrapper {
private final String body;
/**
*
* @param request
*/
public BodyCacheReaderRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder sb = new StringBuilder();
InputStream ins = request.getInputStream();
BufferedReader isr = null;
try{
if(ins != null){
isr = new BufferedReader(new InputStreamReader(ins));
char[] charBuffer = new char[128];
int readCount = 0;
while((readCount = isr.read(charBuffer)) != -1){
sb.append(charBuffer,0,readCount);
}
}else{
sb.append("");
}
}catch (IOException e){
throw e;
}finally {
if(isr != null) {
isr.close();
}
}
sb.toString();
body = sb.toString();
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayIns = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletIns = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayIns.read();
}
};
return servletIns;
}
}