1. 程式人生 > >request&response

request&response

mil cache 而是 壓力 一次 nth 其他應用 ext.get 狀態

HttpServletRequest&HttpServletResponse。

web服務器收到客戶端的http請求,會針對每一次請求,分別創建一個用於代表請求的request對象和代表響應的response對象。如果要獲取客戶機提交的數據,只需要request對象,要想客戶機輸出數據,只需要response對象。

一、Response
1.Resonse的繼承結構:
ServletResponse--HttpServletResponse
2.Response代表響應,於是響應消息中的狀態碼、響應頭、實體內容都可以由它進行操作:
   a.利用Response輸出數據到客戶端

   response.setContentTye("text/html;charset=utf-8");
response.getOUtputStream().write("".getBytes("utf-8"));

response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("");
response.getOutputStream().write("中文".getBytes())輸出數據,這是一個字節流,是什麽字節輸出什麽字節,而瀏覽器默認用平臺字節碼打開服務器發送的數據,如果服務器端使用了非平臺碼去輸出字符的字節數據就需要明確的指定瀏覽器編碼時所用的碼表,以防止亂碼問題。response.setHeader("Content-type","text/html;charset=utf-8")


response.getWriter().write(“中文”);輸出數據,這是一個字符流,response會將此字符進行轉碼操作後輸出到瀏覽器,這個過程默認使用ISO8859-1碼表,而ISO8859-1中沒有中文,於是轉碼過程中用?代替了中文,導致亂碼問題。可以指定response在轉碼過程中使用的目標碼表,防止亂碼。response.setCharcterEncoding("utf-8");
其實response還提供了setContentType("text/html;charset=gb2312")方法,此方法會設置content-type響應頭,通知瀏覽器打開的碼表,同時設置response的轉碼用碼表,從而一行代碼解決亂碼。
  b.利用Response 設置 content-disposition頭實現文件下載
設置響應頭content-disposition為“attachment;filename=xxx.xxx”

      response.setHeader("context-disposition","attachment;filename=xxx.xxx")
利用流將文件讀取進來,再利用Response獲取響應流輸出
如果文件名為中文,一定要進行URL編碼,編碼所用的碼表一定要是utf-8
  c.refresh頭控制定時刷新
設置響應頭Refresh為一個數值,指定多少秒後刷新當前頁面 response.setHeader(refresh","1")
設置響應頭Refresh為 3;url=/Day05/index.jsp,指定多少秒後刷新到哪個頁面 response.setHeader("refresh","3;url=/Day05/index.jsp")
可以用來實現註冊後“註冊成功,3秒後跳轉到主頁”的功能
在HTML可以利用<meta http-equiv= "" content="">標簽模擬響應頭的功能。
  d.利用response設置expires、Cache-Control、Pragma實現瀏覽器是否緩存資源,這三個頭都可以實現,但是由於歷史原因,不同瀏覽器實現不同,所以一般配合這三個頭使用
  控制瀏覽器不要緩存(驗證碼圖片不緩存)設置expires為0或-1設置Cache-Control為no-cache、Pragma為no-cache
  控制瀏覽器緩存資源。即使不明確指定瀏覽器也會緩存資源,這種緩存沒有截至日期。當在地址欄重新輸入地址時會用緩存,但是當刷新或重新開瀏覽器訪問時會重新獲得資源。
如果明確指定緩存時間,瀏覽器緩存是,會有一個截至日期,在截至日期到期之前,當在地址欄重新輸入地址或重新開瀏覽器訪問時都會用緩存,而當刷新時會重新獲得資源。

    response.setIntHeader("Expires",-1) response.setDateHeader("Expires",System.cuurrentTimeMillis()+10001*3600*24*30)

    response.setHeader("Cache-Control","no-cache")

    response.setHeader("Pragma","no-cache")
  e.Response實現請求重定向(地址欄發生改變)
    古老方法:response.setStatus(302);response.addHeader("Location","URL");
    快捷方式:response.sendRedirect("URL");
  f.輸出驗證碼圖片

3.Response註意的內容:
3.1對於一次請求,Response的getOutputStream方法和getWriter方法是互斥,只能調用其一,特別註意forward後也不要違反這一規則。
3.2利用Response輸出數據的時候,並不是直接將數據寫給瀏覽器,而是寫到了Response的緩沖區中,等到整個service方法返回後,由服務器拿出response中的信息組成HTTP響應消息返回給瀏覽器。
3.3service方法返回後,服務器會自己檢查Response獲取的OutputStream或者Writer是否關閉,如果沒有關閉,服務器自動幫你關閉,一般情況下不要自己關閉這兩個流。


二、Request:ServletRequest--HttpServletRequest

  Request代表請求對象,其中封裝了對請求中具有請求行、請求頭、實體內容的操作的方法
1.獲取客戶機信息
getRequestURL方法返回客戶端發出請求完整URL
getRequestURI方法返回請求行中的資源名部分,在權限控制中常用
getQueryString 方法返回請求行中的參數部分
getRemoteAddr方法返回發出請求的客戶機的IP地址
getMethod得到客戶機請求方式
getContextPath 獲得當前web應用虛擬目錄名稱,特別重要!!!,工程中所有的路徑請不要寫死,其中的web應用名要以此方法去獲得。

2.獲取請求頭信息
getHeader(name)方法 --- String ,獲取指定名稱的請求頭的值
getHeaders(String name)方法 --- Enumeration<String> ,獲取指定名稱的請求頭的值的集合,因為可能出現多個重名的請求頭
getHeaderNames方法 --- Enumeration<String> ,獲取所有請求頭名稱組成的集合
getIntHeader(name)方法 --- int ,獲取int類型的請求頭的值
getDateHeader(name)方法 --- long(日期對應毫秒) ,獲取一個日期型的請求頭的值,返回的是一個long值,從1970年1月1日0時開始的毫秒值

*實驗:通過referer信息防盜鏈
String ref = request.getHeader("Referer");
if (ref == null || ref == "" || !ref.startsWith("http://localhost")) {
response.sendRedirect(request.getContextPath() + "/homePage.html");
} else {
this.getServletContext().getRequestDispatcher("/WEB-INF/ethan0603.html").forward(request, response);
}
3.獲取請求參數
getParameter(name) --- String 通過name獲得值
getParameterValues(name) --- String[ ] 通過name獲得多值 checkbox
getParameterNames --- Enumeration<String> 獲得所有請求參數名稱組成的枚舉
getParameterMap --- Map<String,String[ ]> 獲取所有請求參數的組成的Map集合,註意,其中的鍵為String,值為String[]

獲取請求參數時亂碼問題:
瀏覽器發送的請求參數使用什麽編碼呢?當初瀏覽器打開網頁時使用什麽編碼,發送就用什麽編碼。
服務器端獲取到發過來的請求參數默認使用ISO8859-1進行解碼操作,中文一定有亂碼問題
對於Post方式提交的數據,可以設置request.setCharacterEncoding("gb2312");來明確指定獲取請求參數時使用編碼。但是此種方式只對Post方式提交有效。
對於Get方式提交的數據,就只能手動解決亂碼:String newName = new String(name.getBytes("ISO8859-1"),"gb2312");此種方法對Post方式同樣有效。
在tomcat的server.xml中可以配置http連接器的URIEncoding可以指定服務器在獲取請求參數時默認使用的編碼,從而一勞永逸的決絕獲取請求參數時的亂碼問題。也可以指定useBodyEncodingForURI參數,令request.setCharacterEncoding也對GET方式的請求起作用,但是這倆屬性都不推薦使用,因為發布環境往往不允許修改此屬性。


4.利用請求域傳遞對象
生命周期:在service方法調用之前由服務器創建,傳入service方法。整個請求結束,request生命結束。
作用範圍:整個請求鏈。
作用:在整個請求鏈中共享數據,最常用的:在Servlet中處理好的數據要交給Jsp顯示,此時參數就可以放置在Request域中帶過去。

  setAttribute、getAttribute、removeAttribute

5.request實現請求轉發
ServletContext可以實現請求轉發,request也可以。

    this.getServletConttext().getRequestDispatcher("").forward(request,response);

    request.getRequestDispatcher("").forward(request,response);
在forward之前輸入到response緩沖區中的數據,如果已經被發送到了客戶端,forward將失敗,拋出異常,即進行了response.getWriter().flush()刷新
在forward之前輸入到response緩沖區中的數據,但是還沒有發送到客戶端,forward可以執行,但是緩沖區將被清空,之前的數據丟失。註意丟失的只是請求體中的內容,頭內容仍然有效。
在一個Servlet中進行多次forward也是不行的,因為第一次forward結束,response已經被提交了,沒有機會再forward了
總之,一條原則,一次請求只能有一次響應,響應提交走後,就再沒有機會輸出數據給瀏覽器了。

6.RequestDispatcher進行include操作
forward沒有辦法將多個servlet的輸出組成一個輸出,因此RequestDispatcher提供了include方法,可以將多個Servlet的輸出組成一個輸出返回個瀏覽器
request.getRequestDispatcher("/servlet/Demo17Servlet").include(request, response);
response.getWriter().write("from Demo16");
request.getRequestDispatcher("/servlet/Demo18Servlet").include(request, response);
常用在頁面的固定部分單獨寫入一個文件,在多個頁面中include進來簡化代碼量。

  



四、URL編碼
1.由於HTTP協議規定URL路徑中只能存在ASCII碼中的字符,所以如果URL中存在中文或特殊字符需要進行URL編碼。
2.編碼原理:
將空格轉換為加號(+)
對0-9,a-z,A-Z之間的字符保持不變
對於所有其他的字符,用這個字符的當前字符集編碼在內存中的十六進制格式表示,並在每個字節前加上一個百分號(%)。如字符“+”用%2B表示,字符“=”用%3D表示,字符“&”用%26表示,每個中文字符在內存中占兩個字節,字符“中”用%D6%D0表示,字符“國”用%B9%FA表示調對於空格也可以直接使用其十六進制編碼方式,即用%20表示,而不是將它轉換成加號(+)
說明:
如果確信URL串的特殊字符沒有引起使用上的岐義或沖突你也可以對這些字符不進行編碼,而是直接傳遞給服務器。例如,http://www.it315.org/dealregister.html?name=中國&password=123
如果URL串中的特殊字符可能會產生岐義或沖突,則必須對這些特殊字符進行URL編碼。例如,服務器會將不編碼的“中+國”當作“中國”處理。還例如,當name參數值為“中&國”時,如果不對其中的“&”編碼,URL字符串將有如下形式:http://www.it315.org/dealregister.html?name=中&國&password=123,應編碼為:http://www.it315.org/dealregister.html?name=中%26國&password=123
http://www.it315.org/example/index.html#section2可改寫成http://www.it315.org/example%2Findex.html%23section2
3.在java中進行URL編碼和解碼
URLencoder.encode("xxxx","utf-8");
URLDecoder.decode(str,"utf-8");


五、請求重定向和請求轉發的區別
1.區別
RequestDispatcher.forward方法只能將請求轉發給同一個WEB應用中的組件;而HttpServletResponse.sendRedirect 方法還可以重定向到同一個站點上的其他應用程序中的資源,甚至是使用絕對URL重定向到其他站點的資源。
如果傳遞給HttpServletResponse.sendRedirect 方法的相對URL以“/”開頭,它是相對於服務器的根目錄;如果創建RequestDispatcher對象時指定的相對URL以“/”開頭,它是相對於當前WEB應用程序的根目錄。
調用HttpServletResponse.sendRedirect方法重定向的訪問過程結束後,瀏覽器地址欄中顯示的URL會發生改變,由初始的URL地址變成重定向的目標URL;調用RequestDispatcher.forward 方法的請求轉發過程結束後,瀏覽器地址欄保持初始的URL地址不變。
HttpServletResponse.sendRedirect方法對瀏覽器的請求直接作出響應,響應的結果就是告訴瀏覽器去重新發出對另外一個URL的訪問請求;RequestDispatcher.forward方法在服務器端內部將請求轉發給另外一個資源,瀏覽器只知道發出了請求並得到了響應結果,並不知道在服務器程序內部發生了轉發行為。
RequestDispatcher.forward方法的調用者與被調用者之間共享相同的request對象和response對象,它們屬於同一個訪問請求和響應過程;而HttpServletResponse.sendRedirect方法調用者與被調用者使用各自的request對象和response對象,它們屬於兩個獨立的訪問請求和響應過程。
2.應用場景(參照圖想)
通常情況下都用請求轉發,減少服務器壓力
當需要更新地址欄時用請求重定向,如註冊成功後跳轉到主頁。
當需要刷新更新操作時用請求重定向,如購物車付款的操作。

六、常用地址的寫法:
絕對路徑:以/開頭的路徑就叫做絕對路徑,絕對路徑在相對於的路徑上直接拼接得到最終的路徑
相對路徑:不以/開頭的路徑就叫做相對路徑,相對路徑基於當前所在的路徑計算的到最終的路徑
硬盤路徑:以盤符開頭的路徑就叫做硬盤路徑.是哪個路徑就是哪個路徑.沒有相對於誰的問題

虛擬路徑: --寫虛擬路徑時都使用絕對路徑
如果路徑是給瀏覽器用的,這個路徑相對於虛擬主機,所以需要寫上web應用的名稱
如果路徑是個服務器用的,這個路徑相對於web應用,所以可以省寫web應用的名稱
<a href="/Day04/.....">
<form action="/Day04/...">
<img src="/Day04/....">
response.setHeader("Location","/Day04/....");
response.setHeader("refresh","3;url=/Day04/...");
response.sendRedirect("/Day04/...");
request.getRequestDispathce("/index.jsp").forward();
request.getRequestDispathce("/index.jsp").include();

真實路徑: --寫真實路徑時都使用相對路徑
根據原理,具體問題具體分析

servletContext.getRealPath("config.properties");//--給一個相對於web應用目錄的路徑
classLoader.getResource("../../config.properties");//--給一個相對於類加載目錄的路徑

File file = new File("config.properties");//--相對於程序的啟動目錄
new InputStream("config.properties");//--相對於程序的啟動目錄

request&response