Web容器自動對HTTP請求中引數進行URLDecode處理
如題,在Java中也許很多人都沒有注意到當我們傳送一個http請求時,如果附帶的引數被URLEncode之後,到達web容器之後,開發者獲取到的引數值會自動變成了encode之前的值。這是一個很好的特點,開發者完全可以忽略http的引數是否需要decode這種事,但是decode到底是在什麼發生的呢?
第一步就是從request.getParameter()方法下手,但是ServletRequest只是一個介面,是J2EE定義的Servlet框架的一個基本介面,具體實現還是得看具體的Servlet容器,即Web容器,我用的是JBOSS,所以就從JBOSS中原始碼著手。同時為了找出當我們呼叫request.getParameter()時具體是呼叫哪個ServletRequest物件的方法,使用了反射來查詢,程式碼如下:
System.out.println(request.getClass().getName());
- 1
很簡單,通過request的getClass獲取物件的具體名稱,得到的結果是:org.apache.catalina.connector.RequestFacade。可見是Web容器提供的具體ServletRequest實現類,既然找到了具體的類接下來肯定是去看下API文件,看看有沒有提到會對request引數值進行decode操作,順便說下org.apache.catalina.connector.RequestFacade時Tomcat的API,果然文件並未提到任何關於decode的內容,反倒看到RequestFacade僅僅是一個包裝器,真正工作的竟然另有其人,好吧,只能找到程式碼了。
找到RequestFacade的原始碼,發現真正用於獲取request引數的類是RequestFacade的一個受保護的變數request,當然這個類也是實現了ServletRequest介面的。繼續檢視Request原始碼,發現真正幹活的類還不是它,Request內部還有一個變數org.apache.coyote.Request.coyoteRequest,繼續找到org.apache.coyote.Request原始碼。找到org.apache.coyote.Request原始碼大致就已經可以看出到底是什麼時候進行的decode操作了。在org.apache.coyote.Request的構造器中可以看見:
public Request() { this.parameters.setQuery(this.queryMB); this.parameters.setURLDecoder(this.urlDecoder); this.parameters.setHeaders(this.headers); this.methodMB.setString("GET"); this.uriMB.setString("/"); this.queryMB.setString(""); this.protoMB.setString("HTTP/1.0"); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
其中一句this.parameters.setURLDecoder(this.urlDecoder);指定了URLDecoder工具類,再來看看parameters可以看到該類就是用來解析http請求引數的類,該類會使用URLDecoder工具類對請求的name以及value進行decode操作,到這裡基本就已經看到了HTTP請求中的引數到底是如何被自動decode的了。其中並沒有去深究程式碼步驟,畢竟我們只要知道是什麼進行的decode即可。
從上面的整個流程可以看出,對HTTP引數進行自動decode是Web容器依賴的,即並非J2EE標準,所以其他Web容器有可能並未做這種操作,所以開發者還是得注意。