Tomcat是如何處理請求參數(shù)的?

本次以GET請求為例,來分析下Tomcat對請求參數(shù)的處理方式。

說起請求參數(shù),首先我們得了解下,請求參數(shù)的定義。我們一般的請求形式類似下面的樣子:
http://hostName:port/contextName/query?parameName1=paramValue1&parameName2=paramValue2

參照上面的請求格式,url請求中帶參數(shù)的形式(即我們常說的GET請求),是在請求目標后以問號開始,后面是參數(shù)名值對,多個名值對間以和號(&)分隔。
以下是HTTP規(guī)范RFC2616中對此的定義:


通過URL傳遞的參數(shù),在Tomcat中是怎么解析出來的呢?
我們一般在Servlet中要獲取某個參數(shù),一般通過如下的方式
String value = request.getParameter("paramName");

我們在需要的時候通過參數(shù)名直接取,這個值又是什么設置的?名值對又是如何對應起來的?
我們順著getParameter方法這個藤,來摸摸實現(xiàn)這個瓜。
我們在使用HttpServletRequest這個對象時,其實一直在使用的是其一個門面對象(RequestFacade),此對象使用了設計模式中的門面模式,封裝了HttpServletRequest中的一些細節(jié),只暴露出一些必要的API。

實際請求處理時,則調用其封裝的request對象。

getParameter方法的代碼是下面這個樣子:

/ * Return the value of the specified request parameter, if any; otherwise,

  • return <code>null</code>. If there is more than one value defined,
  • return only the first one.
  • @param name Name of the desired request parameter
    */
    public String getParameter(String name) {

if (!parametersParsed) {
parseParameters();
}
return coyoteRequest.getParameters().getParameter(name);
}

每次請求時,會先判斷參數(shù)是否已經解析過,如果已經解析過就直接返回。
protected void parseParameters() {
parametersParsed = true; //注意這里,解析之后就設為true了。
Parameters parameters = coyoteRequest.getParameters();
boolean success = false;
try {
// Set this every time in case limit has been changed via JMX
parameters.setLimit(getConnector().getMaxParameterCount());
}
...
parameters.handleQueryParameters();
}
所以,這個名值對的配置,初始化,是發(fā)生在第一次調用getParameter方法時。

再向下,這個handleQueryParameters是具體處理的方法。這里我們假設請求如下url:
http://localhost:8080/test?abc=1&def=2
在handleQueryParameters方法中,我們通過debug界面觀察到如下內容:


此處parameters包含一個屬性queryMB,其值剛好是我們傳進來的字符串。所以后面的參數(shù)處理,是基于這個屬性進行的。
再之后,在Parameter這個類的processParameter方法中,我們看到的是這樣樣子的處理方式:

我們看到,基本是遍歷字符串中的各個char,遇到特定字符=和&之后,再從各個index獲取等號前后的名和值。
中間特別的一個地方是,遇到%和+時,是出現(xiàn)了像漢字一類的,其實是需要轉義的,所以處理也是在此進行的

解析后,名值對是存放在ArrayList這樣一個數(shù)據(jù)結構中??聪旅娴拇a,
public void addParameter( String key, String value ) {
ArrayList<String> values = paramHashValues.get(key);
if (values == null) {
values = new ArrayList<>(1);
paramHashValues.put(key, values);
}
values.add(value);
}
是執(zhí)行完上面的方法后,代碼向下執(zhí)行,看到的parameters這個對象,值已經變成了這樣:
abc=1,\n def=2,\n

注意上面代碼標紅加粗的這兩行,

你是否還記得上面提到,如果多個參數(shù),對于重名的只返回第一個符合的項這件事?

具體request的參數(shù)請求中,如果不涉及初次處理,那執(zhí)行的是下面的代碼,很簡單,就是直接從Map里取對應key的ArrayList,有值的話就從中取第一個值。

public String getParameter(String name ) {
handleQueryParameters();
ArrayList<String> values = paramHashValues.get(name);
if (values != null) {
if(values.size() == 0) {
return "";
}
return values.get(0); //注意這里,就是在兌現(xiàn)只返回第一個的承諾!!!
} else {
return null;
}
}

和我們直觀理解上基本一致,我們深入代碼,更多的是一起看一些細節(jié)上的東西,比如重名時返回第一項,比如實現(xiàn)過程中使用的數(shù)據(jù)結構等。

將本號推薦給你更多的朋友,大家一起交流。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,525評論 19 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,628評論 18 399
  • 一. Java基礎部分.................................................
    wy_sure閱讀 3,995評論 0 11
  • 1、不安全的隨機數(shù)生成,在CSRF TOKEN生成、password reset token生成等,會造成toke...
    nightmare丿閱讀 3,991評論 0 1
  • 好多年不敢仔仔細細看媽媽,背比以前更駝了,接個電話要叫三四個名,一會叫妹妹,一會叫哥哥,一會又說是不是弟弟。 有時...
    恰媽閱讀 499評論 3 5

友情鏈接更多精彩內容