• Servlet3.1学习(三)


    Filter

    过滤器(Filter)可以修改HTTP请求的内容、响应、Header等信息,过滤器可以包装请求、响应,比如防止XSS攻击等,过滤器同样也可以拦截不安全的请求,比如防止CSRF攻击等等。

    生命周期

    Filter生命周期与Servlet生命周期类似,init()初始化Filter、destory()在销毁时调用、doFilter()负责处理过滤响应和请求。

    包装响应、请求
    Filter最核心的概念就是包装请求或响应,以便它可以执行新的行为。Servlet提供HttpServletRequestWrapper、HttpServletResponseWrapper对象进行包装请求和响应,使用时直接继承即可。

    下面是防止XSS攻击,进行请求包装

    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进行包装,部分代码如下:

    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和RequestDispatcher

    从Servlet2.4之后我们可用使用forward()和include()进行请求分派,同样Filter同样可以拦截分派的请求。

    在配置Filter-Mapping时有元素,指定该Filter拦截那种请求

    • REQUEST:拦截客户端请求,Filter-Mapping默认就是该类型
    • FORWARD:拦截forward()分派请求
    • INCLUDE:拦截include()分派请求
    • ASYNC:拦截异步请求
    • ERROR:拦截错误请求

    配置如下

    <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>
    

    Listener

    事件监听器能够控制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) {
            // 省略部分代码逻辑
        }
    }
    

    Cookie和Session

    由于HTTP是无状态的基于请求/响应模式的协议。在构建有效的Web应用,必须与来自特定客户端的请求彼此相互关联,就是会话跟踪机制。会话跟踪机制有cookie-session、无状态的JWT、token-session机制,这里主要说的是cookie-session会话机制。

    Cookie和Session在Servlet中如何使用就不说了,这里主要说一下自己在应用过程中遇到的问题

    • Cookie的domain:Cookie中的domain指的是该cookie在该domain(域名或IP地址)下有效,在浏览器中只能看到domian下的cookie。
    • Cookie的http-only:Cookie中的Http-Only选项指的是该Cookie是否只能Http请求使用,主要是防止CSRF攻击。
    • 分布式下的Session:由于Session代表用户,所以每个用户应该有唯一的Session。一般情况下,分布式环境下集中存放Session,例如使用Redis集中存放Session,所以就出现了Spring Session进行集中式存放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 {
            // 省略代码
        }
    }
    
  • 相关阅读:
    封装Web Uploader 上传插件、My97DatePicker、百度 编辑器 的使用 (ASP.NET MVC)
    记一次 Newtonsoft.Json 巧妙的用法(C#)
    使用 ItextSharp HTML生成Pdf(C#)
    go 发布
    Winform 使用DotNetBar 根据菜单加载TabControl
    Winform 使用DotNetBar 设置界面为Office2007 样式
    DataTable 导出到TXT
    (Winform程序带源码) 弹出输入框和获取输入框的值
    C# 返回指定目录下所有文件信息
    Winform 应用DotnetBar
  • 原文地址:https://www.cnblogs.com/maying3010/p/8473092.html
Copyright © 2020-2023  润新知