Java 中的 request 和response 理解


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會將包含的資源處理下,之后在處理自己的頁面。 
例子:
[java] view plain copy
  1. package com.enterise.always.servlet;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.RequestDispatcher;  
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.HttpServlet;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10. import javax.servlet.http.HttpSession;  
  11.   
  12. public class Servlet_05 extends HttpServlet{  
  13.     private static final long serialVersionUID = 1L;  
  14.   
  15.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
  16.             throws ServletException, IOException {  
  17.         this.doPost(req, resp);  
  18.     }  
  19.   
  20.     protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
  21.             throws ServletException, IOException {  
  22.         //1.請求轉發  
  23. //      RequestDispatcher requestDispatcher = req.getRequestDispatcher("/index.jsp");  
  24. //      requestDispatcher.forward(req, resp);  
  25. //      requestDispatcher.include(req, resp);  
  26.           
  27.         //2.請求重定向:  
  28. //      resp.sendRedirect("http://localhost:8080/Servlet/servlet/Servlet_03");  
  29.           
  30.         //3.include和forward的區別  
  31.           
  32.         RequestDispatcher requestDispatcher = req.getRequestDispatcher("/servlet/Servlet_03");  
  33.         requestDispatcher.forward(req, resp);  
  34. //      requestDispatcher.include(req, resp);  
  35.           
  36.         resp.getOutputStream().write("Servlet_05".getBytes());  
  37.           
  38.           
  39.     }  
  40. }  
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"));
[java] view plain copy
  1. package com.enterise.always.servlet;  
  2.   
  3.   
  4. import java.io.FileInputStream;  
  5. import java.io.IOException;  
  6. import java.io.OutputStream;  
  7. import java.net.URLEncoder;  
  8.   
  9.   
  10. import javax.servlet.ServletException;  
  11. import javax.servlet.http.HttpServlet;  
  12. import javax.servlet.http.HttpServletRequest;  
  13. import javax.servlet.http.HttpServletResponse;  
  14.   
  15.   
  16. public class Servlet_06 extends HttpServlet{  
  17.     private static final long serialVersionUID = 1L;  
  18.   
  19.   
  20.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
  21.             throws ServletException, IOException {  
  22.         this.doPost(req, resp);  
  23.     }  
  24.   
  25.   
  26.     protected void doPost(HttpServletRequest req, HttpServletResponse response)  
  27.             throws ServletException, IOException {  
  28.         //獲取到下載資源的絕對路徑getRealPath("e://aa/aa.jpg");  
  29.         String path = "e://aa/aa.jpg";  
  30.         String filename = path.substring(path.lastIndexOf("\\")+1);  
  31.           
  32.         //對於中文文件名,如果想正常,一定要經過url編碼  
  33.         response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));  
  34.           
  35.         FileInputStream in = new FileInputStream(path);  
  36.         OutputStream out = response.getOutputStream();  
  37.         try {  
  38.             int len = 0;  
  39.             byte buffer[] = new byte[1024];  
  40.             while ((len = in.read(buffer)) > 0) {  
  41.                 out.write(buffer, 0, len);  
  42.             }  
  43.         } finally {  
  44.             if (in != null)  
  45.                 try {  
  46.                     in.close();  
  47.                 } catch (Exception e) {  
  48.                 }  
  49.             ;  
  50.             if (out != null)  
  51.                 try {  
  52.                     out.close();  
  53.                 } catch (Exception e) {  
  54.                 }  
  55.             ;  
  56.         }  
  57.           
  58.     }  
  59.   
  60.   
  61.       
  62.       
  63. }  
302狀態碼和location頭即可實現重定向


response.setStatus(302);
response.setHeader("location","/Servlet/index.jsp");


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM