1. 程式人生 > >Java Web開發中,自定義過濾器被執行兩次的原因分析及解決辦法

Java Web開發中,自定義過濾器被執行兩次的原因分析及解決辦法

本文出處:http://blog.csdn.net/chaijunkun/article/details/7646338,轉載請註明。由於本人不定期會整理相關博文,會對相應內容作出完善。因此強烈建議在原始出處檢視此文。
在Java Web開發過程中,我們可以使用過濾器和Spring框架提供的攔截器來對請求進行處理,從而實現對整個Web應用的許可權控制。在這裡我簡單介紹一下我在使用過濾器實現許可權驗證方面的經驗。
過濾器作為傳統的Web開發技術,不受使用了第三方框架的束縛,所有符合標準的Servlet容器都支援這項技術。URL字元編碼過濾器是我們經常使用的,而許可權控制過濾器則是過濾器輕量級應用的常見場景。目前我所開發的一個專案中就使用了這項技術,然而在開發時遇到了過濾器被呼叫了兩次的問題,下面說一下我的配置:

在web.xml中我指定了過濾器:

<!--許可權過濾器 -->
	<filter>
		<filter-name>permissionFilter</filter-name>
		<filter-class>blog.csdn.net.chaijunkun.PermissionFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>permissionFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

下面是過濾器的實現程式碼:
package blog.csdn.net.chaijunkun;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

public class PermissionFilter implements Filter {

	private Logger logger= Logger.getLogger(PermissionFilter.class);

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain filterChain) throws IOException, ServletException {
		HttpServletRequest request= (HttpServletRequest) req;
		    logger.info("過濾器被呼叫");
		    filterChain.doFilter(request, resp);
		}
		
	}

	@Override
	public void init(FilterConfig config) throws ServletException {
	}

}

結果當我訪問了一個介面後,在控制檯顯示了兩條“過濾器被呼叫”的提示。後來在網上尋找原因,偶然看到了有人問同樣的問題:http://topic.csdn.net/u/20110930/22/d8741022-53eb-4df1-ace0-357f6edabee1.html
按照“xiaobluesky”說的方法,列印了一下請求的URL地址:System.out.println(request.getRequestedURI());
發現兩次列印的內容不一樣:
第一次列印的是我請求的Servlet,第二次列印的是/favicon.ico,此時才恍然大悟,很多瀏覽器都支援“站點圖示”的功能。例如我當前正在編輯這篇文章,使用的是Chrome瀏覽器,標籤頁上就顯示了一個這樣的CSDN的圖示:

CSDN圖示


根據規範,這個圖示的位置就是在站點根目錄下,命名也必須為favicon.ico。
過濾器被執行兩次的情況僅限於使用Servlet容器既提供靜態訪問支援、又提供動態訪問支援的情況,當採用動靜態分離的場合(例如apache+tomcat,apache將靜態請求攔截自己處理,tomcat只處理動態內容),這種問題自然而然就消失了,因為該請求不會到達Servlet容器。


既然知道了原理,解決起來就好辦了,寫幾個正則表示式,按照requestURI的規劃進行合理的分配,不同的訪問URL採用不同的許可權過濾機制即可。但是這種方法並不能阻止doFilter方法被呼叫兩次,只是程式碼在按照我們指定的請求邏輯上執行。也許,這就是過濾器的不足之處。


也許寫到這裡你會問,為什麼在web.xml配置檔案中url-pattern一定要寫成"/*"這種形式呢?寫成“/*.do”這種形式不是更好麼?我又何嘗不想這樣呢,查了資料並實踐後才知道,這樣寫是不符合JSR-315規範的。有興趣的朋友可以參閱帖子:
http://topic.csdn.net/u/20100525/12/41569c26-350b-45f9-abc0-2019cbb4641b.html
讀一下JSR 315 12.2 節的原文