过滤器(Filter)能够修改HTTP请求的内容、响应、Header等信息,过滤器能够包装请求、响应,好比防止XSS攻击等,过滤器一样也能够拦截不安全的请求,好比防止CSRF攻击等等。html
生命周期java
Filter生命周期与Servlet生命周期相似,init()初始化Filter、destory()在销毁时调用、doFilter()负责处理过滤响应和请求。浏览器
包装响应、请求 Filter最核心的概念就是包装请求或响应,以便它能够执行新的行为。Servlet提供HttpServletRequestWrapper、HttpServletResponseWrapper对象进行包装请求和响应,使用时直接继承便可。安全
下面是防止XSS攻击,进行请求包装cookie
private static class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { XssHttpServletRequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); } @Override public String getHeader(String name) { return HtmlUtils.htmlEscape(super.getHeader(name)); } @Override public String getQueryString() { return HtmlUtils.htmlEscape(super.getQueryString()); } @Override public String getParameter(String parameter) { return HtmlUtils.htmlEscape(super.getParameter(parameter)); } @Override public String[] getParameterValues(String parameter) { String[] values = super.getParameterValues(parameter); if (values == null) { return null; } for (int i = 0; i < values.length; i++) { values[i] = HtmlUtils.htmlEscape(values[i]); } return values; } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> paramMap = new HashMap<>(super.getParameterMap()); for (Map.Entry<String, String[]> entry : paramMap.entrySet()) { String[] values = entry.getValue(); String[] after = new String[values.length]; int index = 0; for (String value : values) { after[index++] = HtmlUtils.htmlEscape(value); } entry.setValue(after); } return paramMap; } } }
Spring Session就是使用Wrapper把获取Session的API进行包装,部分代码以下:session
public class SessionRepositoryFilter<S extends ExpiringSession> extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository); SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper( request, response, this.servletContext); SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper( wrappedRequest, response); HttpServletRequest strategyRequest = this.httpSessionStrategy .wrapRequest(wrappedRequest, wrappedResponse); HttpServletResponse strategyResponse = this.httpSessionStrategy .wrapResponse(wrappedRequest, wrappedResponse); try { filterChain.doFilter(strategyRequest, strategyResponse); } finally { wrappedRequest.commitSession(); } } }
Filter和RequestDispatcherapp
从Servlet2.4以后咱们可用使用forward()和include()进行请求分派,一样Filter一样能够拦截分派的请求。cors
在配置Filter-Mapping时有<dispatcher>元素,指定该Filter拦截那种请求dom
配置以下异步
<filter> <filter-name>corsFilter</filter-name> <filter-class>com.kanyuxia.servlet.chapter.filter.CrossOriginFilter</filer-class> </filter> <filter-mapping> <filter-name>corsFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>FORWARD</dispatcher> </filter-mapping>
事件监听器可以控制ServletContext、HttpSession和ServletRequest的生命周期相关的活动
监听器接口 | 监听器事件 |
---|---|
ServletContextListener | ServletContextEvent |
ServletContextAttributeListener | ServletContextAttributeEvent |
HttpSessionListener | HttpSessionEvent |
HttpSessionAttributeListener | HttpSessionBindingEvent |
HttpSessionIdListener | HttpSessionEvent |
HttpSessionActivationListener | HttpSessionEvent |
HttpSessionBindingListener | HttpSessionBindingEvent |
ServletRequestListener | ServletRequestEvent |
ServletRequestAttributeListener | ServletRequestAttributeEvent |
AsyncListener | AsyncEvent |
监听器的常见应用于其控制的相关对象的生命周期,咱们能够基于此让全部请求入库
@WebListener public class AccessManager implements ServletRequestListener { @Override public void requestInitialized(ServletRequestEvent requestEvent) { ServletContext context = requestEvent.getServletContext(); ConnectionPool connectionPool = (ConnectionPool) context.getAttribute(ConnectionManager.CONNECTION_POOL_NAME); HttpServletRequest request = (HttpServletRequest)requestEvent.getServletRequest(); recordAccessLog(connectionPool, request); } @Override public void requestDestroyed(ServletRequestEvent requestEvent) {} private void recordAccessLog(ConnectionPool connectionPool, HttpServletRequest request) { // 省略部分代码逻辑 } }
因为HTTP是无状态的基于请求/响应模式的协议。在构建有效的Web应用,必须与来自特定客户端的请求彼此相互关联,就是会话跟踪机制。会话跟踪机制有cookie-session、无状态的JWT、token-session机制,这里主要说的是cookie-session会话机制。
Cookie和Session在Servlet中如何使用就不说了,这里主要说一下本身在应用过程当中遇到的问题
Servlet容器在接受到HTTP请求后,须要选择合适的Servlet处理该请求。选择的Servlet根据URL匹配==最长==上下文路径的Servlet,其中"*"表明匹配任意字符串,最后咱们发现若是"/"会匹配任意的请求。"/"表明"default"的Servlet,Servlet容器会自动注入一个匹配路径为"/"的默认的Servlet,处理静态文件获取、404错误等等。
这是Tomcat9.0.2注入的默认Servlet部分代码
public class DefaultServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Serve the requested resource, including the data content serveResource(request, response, true, fileEncoding); } /** * Serve the specified resource, optionally including the data content. */ protected void serveResource(HttpServletRequest request, HttpServletResponse response, boolean content, String inputEncoding) throws IOException, ServletException { // 省略代码 } }