Servlet3.1學習(三)

Filter

過濾器(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時有 元素,指定該Filter攔截那種請求 dom

  • 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 {
        // 省略代碼
    }
}
相關文章
相關標籤/搜索