by:lubingyanghtml
Servlet就是一個普通的類,只不過這個類可以接受和處理請求,而且作出響應。提到Servlet就繞不開Servlet容器,那麼什麼又是Servlet容器呢?通俗的講就是實現Servlet標準管理輔助Servlet類工做的工具。Servlet和Servlet容器在我看來就是子彈和槍的關係,經過對標準化接口的實現互相配合,彼此依存又獨立發展。在大部分的狀況下咱們又稱Servlet容器爲服務器,經常使用的有Tomcat等。java
HTTP(超文本傳輸協議):是互聯網通訊的基礎,屬於 TCP/IP 模型中的應用層協議,當瀏覽器與服務器進行互相通訊時,須要先創建TCP 鏈接,以後服務器纔會接收瀏覽器的請求信息(request),當接收到信息以後,服務器返回相應的信息(response)。最後瀏覽器接受對服務器的信息應答後,對這些數據進行解釋執行(解析HTML文件和各類資源進行展現)。web
HTTP是一個無狀態的鏈接協議。面試
所謂無狀態:瀏覽器
根據早期的HTTP協議,每次request-reponse時,都要從新創建TCP鏈接。TCP鏈接每次都從新創建,因此服務器沒法知道上次請求和本次請求是否來自於同一個客戶端。所以,HTTP通訊是無狀態(stateless)的。服務器認爲每次請求都是一個全新的請求,不管該請求是否來自同一地址。如今,雖然HTTP協議容許TCP鏈接複用,以節省創建鏈接所耗費的時間,但無狀態的特性依舊被保留。安全
爲了迎接HTTP的到來,首先咱們須要有一個Servlet類,而且告訴Servlet容器本身的存在,這兩個準備步驟就是建立Servlet類和寫入配置文件。服務器
正如上文所講,類和Servlet容器之間的配合是經過接口實現的,一個類只須要實現特定的接口,就能夠稱爲一個Servlet類,而且可以被Servlet所接受,嗯,想來這就是接口的解耦和。cookie
準備一個Servlet類session
擁有一個Servlet類的三種方案mybatis
在直接實現或者間接實現Servlet接口以後咱們須要重寫其中的service方法,到此Servlet就準備好了。
寫入配置文件
配置文件是一個固定的寫法,主要就是爲了告訴Servlet容器本身在哪
<servlet>
<servlet-name>自定義Servlet的別名</servlet-name>
<servlet-class>Servlet類的全類名</servlet-class>
</servlet>
<servlet-mapping>
<servelt-name>自定義Servlet的別名</servelt-name>
<url-pattern>自定義路徑</url-pattern>
</servlet-mapping>
複製代碼
Servlet容器開啓服務以後就能夠迎接request的到來了,當這個HTTP請求到達Servlet容器(以Tomcat爲例)的時候,Tomcat看到有HTTP來,就把它帶到要去的那個地方(項目名),到了地點以後,Tomcat會拿出花名冊(web.xml)讓request挑一個(0.0)。
結果,不用挑有指定的,那就好辦了。
Tomcat在部署文件中找 servlet-mapping 中與之匹配的 url-pattern,根據這個 url-pattern 的 servlet-name 映射到真正的 servlet-class ,而後調用相應的 Servlet 類。
擴展內容:xml
xml全稱是Extensible Markup Language可擴展標記語言,看到這個不免會想起來HTML,他們有什麼關係呢?爲何有了HTML語言還要xml語言呢?
認真的講他們最大的關係就是都以ml結尾了,哈哈,開個玩笑。
HTML咱們是很熟悉的,在使用的時候不難發現其中的標籤都是定義好的,全世界的HTML文檔用的是同一套標記的語法。
而xml更具備個性化,其中的標籤不只能夠用別人的定義好的,也能夠本身定義。書寫一個xml有兩個相關的規則,一個是標籤規則,另外一個就是校檢規則,校檢規則是用來告訴程序標籤之間的規則,這個東西被稱之爲文檔類型定義 Document Type Definition , 簡稱 DTD 這兩個規則都是能夠自定義的(所謂擴展),因此咱們在書寫不一樣的xml文件的時候,會發現標籤規則是不同的。
從這些層面上來講HTML語言也能夠說是xml中的一種,HTML5就是最新的校檢規則(不知道這麼理解有沒有問題???)
<!-- 咱們不難發現不少xml文檔的文檔聲明中都有聲明其文檔符合的校檢規則 --> <!-- web.xml --> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> XML Schema是dtd的改進版 <!-- mybatis-config.xml --> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > 複製代碼
經過以上的步驟Tomcat就找到了HTTP想要見到的那個Servlet了,可是這個類也許準備好了,也許沒有,咱們假定這個request是第一次來。這時候就開始了Servlet的生命週期了。
由於是第一次請求,Tomcat會調用Servlet類的無參構造方法,建立這個Servlet的對象。
以後初始化,會調用init方法,這個方法會對Servlet類作一些初始化的工做,須要注意的這個方法在Servlet的一輩子中只會執行這麼一次。像初始化這麼重要的事兒只進行一次是有現實意義的,畢竟若是能夠屢次的話,我早就一米八了。
初始化以後一個Servlet就正式的進入服務狀態能夠接客了,這時候就會調用service方法,接受HTTP的request,並對這個請求作一些服務項目,剪個頭髮之類啊,最後再把面目全非的請求送走,不,這時候應該叫響應response。據說每次剪頭髮都像整容,惋惜很久沒有剪過頭髮了。
通過第一個請求以後,再有HTTP過來的時候,Servlet會直接調用service方法爲其服務,畢竟誰一生也不能接一個客戶初始化一次吧。
最後當服務關閉的時候,會銷燬這個對象,在銷燬前會調用destroy方法。
寫到會話跟蹤要先從HTTP開始提及,在以前咱們說過HTTP是無狀態的。由於其無狀態的特性,服務器不能以狀態來區分和管理請求和響應,並且一次請求響應以後就會斷開鏈接,因此服務器也不須要保存狀態信息,雖然這樣簡單不佔資源,適用性廣,可是不利之處在於咱們沒有辦法根據HTTP自己對請求作一些區分。
因此爲了在保留無狀態協議這個特徵的同時又解決相似記錄狀態的矛盾問題,出現了Cookie。
從上圖咱們知道,有幾個關鍵性的步驟是須要咱們來作的:
建立Cookie
//參數是cookie的標記和值,必須是英文
Cookie cookie = new Cookie(flag,value);
複製代碼
響應信息中加上Cookie
response.addCookie(cookie);
複製代碼
再次請求到來的時候檢查Cookie
//獲取request中全部的cookie信息
Cookies[] cookies = request.getCookies();
//遍歷檢查cookie
if(cookies != null){
for(Cookie c : cookies){
String name = c.getName();
String value = c.getValue();
}
}
複製代碼
注
cookie是有有效期的,通常會在瀏覽器關閉的時候自動清空
設置cookie有效期,調用方法setMaxAge(60)
cookie中的數據是不安全的,畢竟保存到本地,能夠顯式查看
session是服務器爲每個瀏覽器創建的私人存儲空間,其中(session做用域)能夠存儲瀏覽器的屬性和一些配置信息,當瀏覽器拿到session以後(沒有更換持有的session),在不一樣的Servlet之間跳轉的時候,能夠隨時取出放在做用域中的數據。
上圖是session的基本實現原理,咱們能夠看到session是經過cookie來實現的,具體的步驟是這樣的:
瀏覽器把登陸信息放入HTTP請求報文的實體部分,一般是以POST 方法把請求發送給服務器
服務器建立session,並將用戶信息和session進行綁定記錄在服務器,而後把處理好的session放入cookie中隨着響應發給瀏覽器。
瀏覽器收到服務器響應的帶有session信息的cookie時,會將cookie存在本地,下次請求的時候自動攜帶,服務器會經過接受其中的session對用戶進行驗證。
從本質上來說,區別只有兩點:
那麼咱們常提到的區別是從哪裏來的呢?
從解釋上面的區別開始。
早期的HTTP協議只有GET方法。根據HTTP協議,服務器接收到GET請求後,會將特定資源響應給瀏覽器,GET方法是經過改寫URL實現的,在URL後面加上要傳遞的數據(格式是URL?key=value&key=value......)。因此在使用GET方法請求資源的時候,請求每每是沒有主體的。
那麼問題來了,什麼是主體?
所謂主體就是request的報文主體,咱們知道HTTP請求的報文格式(響應雷同)是這樣的
l 起始行
l 頭信息
l 主體
GET方法的請求報文信息通常只有起始行和頭信息,以下:
<!-- 拼接後的url -->
http://localhost:8801/zhibaxm/servlet/LoginAction?username=%E5%BE%90%E9%80%9A%E8%BE%BE&pwd=123
<!-- 請求頭 -->
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Host:localhost:8801
Origin:http://localhost:8801
Referer:http://localhost:8801/zhibaxm/login.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
複製代碼
而對於POST方法,URL再也不被改寫,相關的表單數據會位於http請求的主體。以下:
<!-- url -->
http://localhost:8801/zhibaxm/servlet/LoginAction
<!-- 請求頭 -->
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Host:localhost:8801
Origin:http://localhost:8801
Referer:http://localhost:8801/zhibaxm/login.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
<!-- POST的主體信息 -->
username=%E5%BE%90%E9%80%9A%E8%BE%BE&pwd=123
複製代碼
咱們知道每個請求都是能夠有三部分的:起始行,請求頭,主體,也就是說,GET和POST的區別不是語法上的,而是規範上的,簡單的說就是,你在使用POST的時候若是把參數寫在url上也是沒有問題的。
可是,咱們在使用中確實有不少的不一樣,咋回事兒呢?這些區別並非語法自己的不一樣,而是因爲瀏覽器和服務器差別形成的使用上的區別,例如:大部分瀏覽器的url長度限制在2K個字節,而大部分服務器最多處理64K大小的url。在使用GET方法時,若是你在報文主體寫入了數據,那麼不一樣服務器的處理方式也是不一樣的,有些服務器會接受有些不會。
形成區別的緣由更多不是來自語法自己,而是不一樣瀏覽器服務器的限制。
扯完了這些,補充一下應用上區別,畢竟遇到面試的時候,使用上的差異也是不可以忘記的,使用上的區別以下:
GET | POST |
---|---|
只能夠接受字符串 | 沒有限制 |
不安全 | 相對安全 |
有長度限制 | 沒有長度限制 |
... | ... |