request和response(請求和響應)
1.當Web容器收到客戶端的發送過來http請求,會針對每一次請求,分別創建一個用於代表此次請求的HttpServletRequest對象(request)對象、和代表響應的HTTPServletResponse對象(response)。
request負責獲取客戶機提交過來的數據。
response負責向客戶機輸出數據。 2.HttpServletRequest請求 GET /Servlet/servlet/Servlet_03 HTTP/1.1 Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, */* Accept-Language: zh-CN User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E) Accept-Encoding: gzip, deflate Host: localhost:8080 Connection: Keep-Alive getRequestURL方法返回客戶端發出請求時的完整URL。 getRequestURI方法返回請求行中的資源名部分。 getQueryString 方法返回請求行中的參數部分。 getRemoteAddr方法返回發出請求的客戶機的IP地址 getRemoteHost方法返回發出請求的客戶機的完整主機名 getRemotePort方法返回客戶機所使用的網絡端口號 getLocalAddr方法返回WEB服務器的IP地址。 getLocalName方法返回WEB服務器的主機名 在request中可以獲取一些請求頭,這些請求頭的案例有: 1.可以用來防盜鏈(Referer頭) 防盜鏈: 有些下載系統的下載地址會有一個下載跳轉,用戶在下載頁面上看到的下載地址可能是 http://www.abc.com/down.asp?id=xxxx 有人直接將這個地址復制到其他地方,即可盜鏈,直接利用下載的地址就可以實現下載,而不是通過我自己的網站去下載,這時我們就需要判斷下是否是通過我自己的網站點擊下載的。 所以我們需要在 down.asp 這個頁面做下簡單的來源判斷。如果不是來自本站的連接,則直接拒絕訪問。 String referer = request.getHeader("referer");//獲取請求頭 //判斷這個頭是否為空,或這個頭的首地址是否為http://localhost,如果不是則重定向 2.獲取表單中的信息: String value = req.getParameter("name"); 在表單提交過來時的中文亂碼的問題: *瀏覽器怎樣進行URL編碼: (1)瀏覽器對FORM表單中輸入的中文字符都會進行URL編碼后再傳送給WEB服務器。 (2)對於頁面中的FORM表單中輸入的內容,瀏覽器將按照當前顯示頁面時所采用的字符集編碼來進行URL編碼。 getParameter方法的中文問題: (1)getParameter等方法在讀取的參數信息時,需要進行URL解碼。 (2)對於HTTP請求消息的請求行中的URL地址后的參數,getParameter等方法進行URL解碼時所采用的字符集編碼在Servlet規范中沒有明確規定Tomcat中的ServletReq uest對象的getParameter等方法默認采用ISO8859-1字符集編碼進行URL解碼,因此無法返回正確的中文參數信息 。 (3)對於POST方式下的“application/x-www-form-urlencoded”編碼格式的實體內容,getParameter等方法以ServletRequest對象的getCharacterEncoding()方法返 回的字符集編碼對其進行URL解碼。 (4)getCharacterEncoding()方法的返回值通常為null,對於這種情況,ServletRequest對象的getParameter等方法將使用默認的ISO8859-1字符集編碼對實體內容中 的參數進行URL解碼,因此也將無法返回正確的中文參數信息。 (5)ServletRequest接口中定義了一個setCharacterEncoding方法來設置請求消息中的實體內容的字符集編碼名稱,getParameter方法將以該方法設置的字符集編碼 對實體內容進行URL解碼。 (6)setCharacterEncoding方法設置的是請求消息中的實體內容的字符集編碼名稱,它只影響getParameter方法對POST方式下的“application/x-www-form-urlencod ed”編碼格式的實體內容進行URL解碼的結果,而不能影響getParameter方法對HTTP請求消息的請求行中的URL地址后的參數進行URL解碼的結果。
解決方案:
1.post方式
對於POST方式,表單中的參數值對是通過request包發送給服務器,此時瀏覽器會根據網頁的ContentType("text/html; charset=GBK")中指定的編碼進行對表單中的數據進行編碼,然后發給服務器。
在服務器中根據:request.setCharacterEncoding(""),只要編碼跟瀏覽器一直的就可以。
2.get方式
對於GET方式,我們知道它的提交是將請求數據附加到URL后面作為參數,這樣依賴亂碼就會很容易出現,因為數據name和value很有可能就是傳遞的為非ASCII碼。
當URL拼接后,瀏覽器對其進行encode,然后發送到服務器。具體規則見URL編碼規則。
這里詳細說一下encode的過程中容易出現的問題,在這個過程中我們要明白需要URL encode的字符一般都是非ASCII碼字符,所以我們就能知道出現亂碼主要是URL中附加了中文或特殊字符做成的,另一個要知道URL encode到底是以什么樣的編碼方式對字符進行編碼的,其實這個編碼方式是由瀏覽器決定的,不同的瀏覽器和同一瀏覽器的不同設置影響了URL的編碼,所以為了避免我們不需要的編碼,我們可以通過java代碼或javaspcript代碼統一進行控制。
完成了URL encode之后URL就成了ASCII范圍內的字符了,然后就以iso-8859-1的編碼方式轉換為二進制隨着請求頭一起發送出去。
到了服務器之后,首先服務器會先用iso-8859-1進行解碼,服務器獲取的數據都是ASCII范圍內的請求頭字符,其中請求URL里面帶有參數數據,如果是中衛或特殊字符,那么encode后的%XY(編碼規則中的十六進制數)通過request.setCharacterEncoding()是不管用的。這時候我們就能發現出現亂碼的根本原因就是客戶端一般是通過用UTF-8或GBK等對數據進行encode的,到了服務器卻用iso-8859-1方式decoder顯然不行。
String value = new String(req.getParameter("name").getBytes("iso-8859-1"),"GBK");
3.request對象實現請求轉發:
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/index.jsp"); requestDispatcher.forward(req, resp); 請求重定向和請求轉發:是Servlet處理完數據后進行頁面跳轉的兩種主要方式 請求轉發: 請求轉發是指將請求再轉發到另一資源(一般為JSP或Servlet)。此過程依然在同一個請求范圍內,轉發后瀏覽器地址欄內 容不變 請求轉發使用RequestDispatcher接口中的forward()方法來實現,該方法可以把請求轉發到另外一個資源,並讓該資源對瀏 覽器的請求進行響應 請求重定向: 重定向是指頁面重新定位到某個新地址,之前的請求失效,進入一個新的請求,且跳轉后瀏覽器地址欄內容將變為新的指定 地址 重定向是通過HttpServletResponse對象的sendRedirect()來實現,該方法相當於瀏覽器重新發送一個請求 //1.請求轉發 RequestDispatcher requestDispatcher = req.getRequestDispatcher("/index.jsp"); requestDispatcher.forward(req, resp); //2.請求重定向: resp.sendRedirect("http://localhost:8080/Servlet/servlet/Servlet_03"); 區別: 1.使用請求重定向,瀏覽器會向服務器發送兩次請求,而請求轉發則為一次請求
2.地址欄顯示不一樣請求轉發地址欄沒有變化,而請求重定向地址欄會顯示新的請求地址
HttpServletResponse.sendRedirect方法和RequestDispatcher.forward方法的區別:
盡管HttpServletResponse.sendRedirect方法和RequestDispatcher.forward方法都可以讓瀏覽器獲得另外一個URL所指向的資源,但
兩者的內部運行機制有着很大的區別。下面是HttpServletResponse.sendRedirect方法實現的請求重定向與
RequestDispatcher.forward方法實現的請求轉發的總結比較:
(1)RequestDispatcher.forward方法只能將請求轉發給同一個WEB應用中的組件;而HttpServletResponse.sendRedirect 方法不僅
可以重定向到當前應用程序中的其他資源,還可以重定向到同一個站點上的其他應用程序中的資源,甚至是使用絕對URL重定向到其
他站點的資源。如果傳遞給HttpServletResponse.sendRedirect 方法的相對URL以“/”開頭,它是相對於整個WEB站點的根目錄;如
果創建RequestDispatcher對象時指定的相對URL以“/”開頭,它是相對於當前WEB應用程序的根目錄。
(2)調用HttpServletResponse.sendRedirect方法重定向的訪問過程結束后,瀏覽器地址欄中顯示的URL會發生改變,由初始的URL
地址變成重定向的目標URL;而調用RequestDispatcher.forward 方法的請求轉發過程結束后,瀏覽器地址欄保持初始的URL地址不變
。
(3)HttpServletResponse.sendRedirect方法對瀏覽器的請求直接作出響應,響應的結果就是告訴瀏覽器去重新發出對另外一個URL
的 訪問請求,這個過程好比有個綽號叫“瀏覽器”的人寫信找張三借錢,張三回信說沒有錢,讓“瀏覽器”去找李四借,並將李四
現在的通信地址告訴給了“瀏覽器”。於是,“瀏覽器”又按張三提供通信地址給李四寫信借錢,李四收到信后就把錢匯給了“瀏覽
器”。可見,“瀏覽器”一共發出了兩封信和收到了兩次回復, “瀏覽器”也知道他借到的錢出自李四之手。
RequestDispatcher.forward方 法在服務器端內部將請求轉發給另外一個資源,瀏覽器只知道發出了請求並得到了響應結果,並不知
道在服務器程序內部發生了轉發行為。這個過程好比綽號叫“瀏覽器”的人寫信找張三借錢,張三沒有錢,於是張三找李四借了一些
錢,甚至還可以加上自己的一些錢,然后再將這些錢匯給了“瀏覽器”。可見,“瀏覽器”只發 出了一封信和收到了一次回復,他
只知道從張三那里借到了錢,並不知道有一部分錢出自李四之手。
(4)RequestDispatcher.forward方法的調用者與被調用者之間共享相同的request對象和response對象,它們屬於同一個訪問請求
和響應過程;而HttpServletResponse.sendRedirect方法調用者與被調用者使用各自的request對象和response對象,它們屬於兩個
獨立的訪問請求和響應過程。對於同一個WEB應用程序的內部資源之間的跳轉,特別是跳轉之前要對請求進行一些前期預處理,並要
使用HttpServletRequest.setAttribute方法傳遞預處理結果,那就應該使用RequestDispatcher.forward方法。不同WEB應用程序之
間的重定向,特別是要重定向到另外一個WEB站點上的資源的情況,都應該使用HttpServletResponse.sendRedirect方法。
(5)無論是RequestDispatcher.forward方法,還是HttpServletResponse.sendRedirect方法,在調用它們之前,都不能有內容已經
被實際輸出到了客戶端。如果緩沖區中已經有了一些內容,這些內容將被從緩沖區中清除。
場景應用:
請求轉發: 用於不同應用場景 一般來講,在MVC設計模式下,一個servlet將數據交給jsp來做顯示就使用請求轉發,因為沒必要讓用戶 知道內部實現原理,同時對jsp頁面也可以做保護 重定向: 用戶登錄成功跳轉到首頁面是用請求重定向,因為此時需要讓用戶明確知道自己登錄成功並跳轉到了首頁 include和forward的區別: forward會轉發到相應的資源中。 而include會將包含的資源處理下,之后在處理自己的頁面。
例子:
- package com.enterise.always.servlet;
-
- import java.io.IOException;
-
- import javax.servlet.RequestDispatcher;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
-
- public class Servlet_05 extends HttpServlet{
- private static final long serialVersionUID = 1L;
-
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- this.doPost(req, resp);
- }
-
- protected void doPost(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
-
-
-
-
-
-
- RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet/Servlet_03");
- requestDispatcher.forward(req, resp);
-
- resp.getOutputStream().write("Servlet_05".getBytes());
-
-
- }
- }
include的結果為:servlet_03Servlet_05
forward的結果為:servlet_03
2.HttpServletResponse
HttpServletResponse對象代表服務器的響應。這個對象中封裝了向客戶端發送數據、發送響應頭,發送響應狀態碼的方法。
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Length: 0
Date: Tue, 03 Sep 2013 03:52:13 GMT
1.getOutputStream和getWriter方法分別用於得到輸出二進制數據、輸出文本數據的ServletOuputStream、Printwriter對象。
但是兩則不能結合在一起使用,原因是:
兩個對象的流不一樣:
getOutputStream:方法用於返回Servlet引擎創建的字節輸出流對象
getWriter:返回Servlet引擎創建的字符輸出流對象
這兩個方法互斥,調用了其中的一個方法之后,就不能在調用另外一個。
Serlvet的service方法結束后,Servlet引擎將檢查getWriter或getOutputStream方法返回的輸出流對象是否已經調用過close方法,
如果沒有,Servlet引擎將調用close方法關閉該輸出流對象。
response的其他功能:
通過setStats方法可以設置響應頭的狀態碼
通過setHead方法可以設置響應頭
常見應用
發送REFRESH頭,控制瀏覽器定時刷新網頁
發送Expires頭,控制瀏覽器禁止緩存當前文檔內容
發送content-type頭通知瀏覽器打開文件的方式
response.setCharacterEncoding("GBK");
//設置瀏覽器定時刷新
response.setHeader("refresh", "3");
response.getWriter().write("定時刷新中");
//設置瀏覽器禁止緩存
response.setDateHeader("Expires", 0);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Prama", "no-cache");
//實現文件的下載
//對於中文文件名,如果想正常,一定要經過url編碼
response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename,
"UTF-8"));
- package com.enterise.always.servlet;
-
-
- import java.io.FileInputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.net.URLEncoder;
-
-
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
-
- public class Servlet_06 extends HttpServlet{
- private static final long serialVersionUID = 1L;
-
-
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- this.doPost(req, resp);
- }
-
-
- protected void doPost(HttpServletRequest req, HttpServletResponse response)
- throws ServletException, IOException {
-
- String path = "e://aa/aa.jpg";
- String filename = path.substring(path.lastIndexOf("\\")+1);
-
-
- response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
-
- FileInputStream in = new FileInputStream(path);
- OutputStream out = response.getOutputStream();
- try {
- int len = 0;
- byte buffer[] = new byte[1024];
- while ((len = in.read(buffer)) > 0) {
- out.write(buffer, 0, len);
- }
- } finally {
- if (in != null)
- try {
- in.close();
- } catch (Exception e) {
- }
- ;
- if (out != null)
- try {
- out.close();
- } catch (Exception e) {
- }
- ;
- }
-
- }
-
-
-
-
- }
302狀態碼和location頭即可實現重定向
response.setStatus(302);
response.setHeader("location","/Servlet/index.jsp");