Java Web
JSP和Servlet區別
JSP是Servlet技術的擴展,本質上就是Servlet的簡易方式。JSP編譯后是"類servlet"。Servlet和JSP最主要的不同點在于,Servlet的應用邏輯是在Java文件中,并且完全從表示層中的HTML里分離開來。而JSP的情況是Java和HTML可以組合成一個擴展名為.jsp的文件。JSP側重于視圖,Servlet主要用于控制邏輯。
Servlet不同版本區別
- 2.3版本:web-app里的標簽有一定的順序
- 2.4版本:多個url不能映射到同一個servlet
- 2.5版本:解決多個url不能映射到同一個servlet的問題。
- 3.0版本:web.xml配置文件中包含: 默認頁配置、session超時配置和錯誤提示頁配置。
JSP內置對象
JSP有9個內置對象:
- request:封裝客戶端的請求,其中包含來自GET或POST請求的參數;
- response:封裝服務器對客戶端的響應;
- session:封裝用戶會話的對象;
- out:輸出服務器響應的輸出流對象;
- page:JSP頁面本身(相當于Java程序中的this);
- pageContext:代表頁面上下文,該對象主要用于訪問JSP之間的共享數據;
- exception:封裝頁面拋出異常的對象。
- application:封裝服務器運行環境的對象;
- config:Web應用的配置對象;
JSP基本動作
JSP 共有以下6種基本動作
- jsp:include:在頁面被請求的時候引入一個文件。
- jsp:forward:把請求轉到一個新的頁面。
- jsp:setProperty:設置JavaBean的屬性。
- jsp:getProperty:輸出某個JavaBean的屬性。
- jsp:useBean:尋找或者實例化一個JavaBean。
- jsp:plugin:根據瀏覽器類型為Java插件生成OBJECT或EMBED標記。
過濾器的作用
Java Web開發中的過濾器(filter)是從Servlet 2.3規范開始增加的功能,并在Servlet 2.4規范中得到增強。對Web應用來說,過濾器是一個駐留在服務器端的Web組件,它可以截取客戶端和服務器之間的請求與響應信息,并對這些信息進行過濾。當Web容器接受到一個對資源的請求時,它將判斷是否有過濾器與這個資源相關聯。如果有,那么容器將把請求交給過濾器進行處理。
在過濾器中,你可以改變請求的內容,或者重新設置請求的報頭信息,然后再將請求發送給目標資源。當目標資源對請求作出響應時候,容器同樣會將響應先轉發給過濾器,在過濾器中你可以對響應的內容進行轉換,然后再將響應發送到客戶端。
常見的過濾器用途主要包括:對用戶請求進行統一認證、對用戶的訪問請求進行記錄和審核、對用戶發送的數據進行過濾或替換、轉換圖像格式、對響應內容進行壓縮以減少傳輸量、對請求或響應進行加解密處理、觸發資源訪問事件、對XML的輸出應用XSLT等。和過濾器相關的接口主要有:Filter、FilterConfig和FilterChain。
forward與redirect區別
- 從地址欄顯示來說
- forward是服務器請求資源,服務器直接訪問目標地址的URL,把那個URL的響應內容讀取過來,然后把這些內容再發給瀏覽器。瀏覽器根本不知道服務器發送的內容從哪里來的,所以它的地址欄還是原來的地址。
- redirect是服務端根據邏輯,發送一個狀態碼,告訴瀏覽器重新去請求那個地址,所以地址欄顯示的是新的URL。
- 從數據共享來說
- forward:轉發頁面和轉發到的頁面可以共享request里面的數據。
- redirect:不能共享數據。
- 從運用地方來說
- forward:一般用于用戶登陸的時候,根據角色轉發到相應的模塊。
- redirect:一般用于用戶注銷登陸時返回主頁面和跳轉到其它的網站等。
- 從效率來說
- forward:高
- redirect:低
標簽庫的好處
- 分離JSP頁面的內容和邏輯,簡化了Web開發;
- 開發者可以創建自定義標簽來封裝業務邏輯和顯示邏輯;
- 標簽具有很好的可移植性、可維護性和可重用性;
- 避免了對Scriptlet(小腳本)的使用
get和post請求
- Get和Post的區別:
- get請求用來從服務器上獲得資源,而post是用來向服務器提交數據;
- get將表單中數據按照name=value的形式,添加到action 所指向的URL 后面,并且兩者使用"?"連接,而各個變量之間使用"&"連接;post是將表單中的數據放在HTTP協議的請求頭或消息體中,傳遞到action所指向URL;
- get傳輸的數據要受到URL長度限制(1024字節);而post可以傳輸大量的數據,上傳文件通常要使用post方式;
- 使用get時參數會顯示在地址欄上,如果這些數據不是敏感數據,那么可以使用get;對于敏感數據還是應用使用post;
- post能發送更多的數據類型(get只能發送ASCII字符)
- post比get慢
- post用于修改和寫入數據,get一般用于搜索排序和篩選之類的操作
- 為什么get比post更快?
- post請求包含更多的請求頭
- post在真正發送數據之前會先將請求頭發送給服務器進行確認,然后才真正發送數據
- get會將數據緩存起來,而post不會
- post不能進行管道化傳輸
- post請求的過程:
- 瀏覽器請求tcp連接(第一次握手)
- 服務器答應進行tcp連接(第二次握手)
- 瀏覽器確認,并發送post請求頭(第三次握手,這個報文比較小,所以http會在此時進行第一次數據發送)
- 服務器返回100 Continue響應
- 瀏覽器發送數據
- 服務器返回200 OK響應
- get請求的過程:
- 瀏覽器請求tcp連接(第一次握手)
- 服務器答應進行tcp連接(第二次握手)
- 瀏覽器確認,并發送get請求頭和數據(第三次握手,這個報文比較小,所以http會在此時進行第一次數據發送)
- 服務器返回200OK響應
也就是說,目測get的總耗是post的2/3左右。
- get傳參最大長度的理解誤區
- http協議并未規定get和post的長度限制
- get的最大長度限制是因為瀏覽器和web服務器限制了URL的長度
- 不同的瀏覽器和web服務器,限制的最大長度不一樣。要支持IE,則最大長度為2083byte,若支持Chrome,則最大長度8182byte;
- 服務器Apache能接受url長度限制為8192 字符;Microsoft Internet Information Server(IIS)能接受url長度限制為16384個字符。這個是可以修改的(IIS7)
支付接口調用兩次,如何防止重復扣款?
- 保證冪等性主要是三點:
- 對于每個請求必須有一個唯一的標識,舉個例子:訂單支付請求,肯定得包含訂單 id,一個訂單 id 最多支付一次。
- 每次處理完請求之后,必須有一個記錄標識這個請求處理過了。常見的方案是在 mysql 中記錄狀態,比如支付之前記錄一條這個訂單的支付流水。
- 每次接收請求需要進行判斷,判斷之前是否處理過。比如說,如果有一個訂單已經支付了,就已經有了一條支付流水,那么如果重復發送這個請求,則此時先插入支付流水,orderId 已經存在了,唯一鍵約束生效,報錯插入不進去的。也就不用再扣款了。
- 實際運作:
- 實際運作過程中,結合自己的業務可以利用 redis,用 orderId 作為唯一鍵。只有成功插入這個支付流水,才可以執行實際的支付扣款。
- 要求是支付一個訂單,必須插入一條支付流水,order_id 建一個唯一鍵 unique key。你在支付一個訂單之前,先插入一條支付流水,order_id 就已經進去了。你就可以寫一個標識到 redis 里面去,set order_id payed,下一次重復請求過來了,先查 redis 的 order_id 對應的 value,如果是 payed 就說明已經支付過了。
cookie 和 session 的區別
- cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
- cookie不是很安全,別人可以分析存放在本地的COOKIE,并進行COOKIE欺騙。
- session會在一定時間內保存在服務器上。當訪問增多,會比較占用服務器的性能。
- 單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。
如何保證cookie的安全性?
- Cookie 依然遵循"同源策略",只有用目標服務器域名設置的 Cookie 才會上傳,而且使用 document.cookie 也無法讀取目標服務器域名下的 Cookie。所以不能跨域獲取cookie數據
- cookie存儲在客戶端,session存儲在服務器端,服務器端有個明細列表,將cookie數據與列表一一對應。
- 服務器傳送cookie時設置屬性secure為true,表示創建的cookie只能在HTTPS連接中,被瀏覽器傳遞到服務器端進行會話驗證,如果是HTTP連接則不會傳遞該信息,所以很難被竊聽到。
- 服務器傳送cookie時設置屬性HttpOnly,HttpOnly告知瀏覽器不允許通過腳本document.cookie去更改這個cookie值,事實上,設置HttpOnly之后,這個值在document.cookie中不可見。但是在HTTP請求的過程中,依然會發送這個Cookie到服務器端。
浙公網安備 33010602011771號