HttpRequest,HttpResponse,亂碼,轉發和重定向


HttpServletRequest簡介

Web服務器收到客戶端的http請求,會針對每一次請求,創建一個用於代表請求的HttpServletRequest類型的request對象,並將"HTTP請求協議"的完整內容封裝到該對象中。開發者獲拿到request對象后就可以獲取客戶端發送給服務器的請求數據了。

HttpServletRequest的生命周期

當客戶端瀏覽器向服務器發送請求后,服務器會根據HTTP請求協議的格式對請求進行解析。同時,服務器會創建 HttpServletRequest類型的對象,即請求對象,然后將解析出的數據封裝到該請求對象中。此時HttpServletRequest實例就創建並初始化完畢了,也就是說,請求對象是由服務器創建。當服務器向客戶端發送響應結束后,HttpServletRequest 實例對象被服務器銷毀,HttpServletRequest對象的生命周期很短暫。
一次請求對應一個請求對象, 另外一次請求對應另外一個請求對象,即每次請求都會創建一個HttpServletRequest類型的對象,這些對象之間沒有關系。

HttpServletRequest中常用的方法

  • Map<string,string[]> getParameterMap()
    獲取包含所有請求參數及值的 Map 對象。需要注意,該 Map 的 value 為 String[],即一個參數所對應的值為一個數組。說明一個參數可以對應多個值。
  • Enumeration getParameterNames()
    獲取請求參數 Map 的所有 key,即獲取所有請求參數名。
  • String[] getParameterValues(String name)
    根據指定的請求參數名稱,獲取其對應的所有值。這個方法一般用於獲取復選框(checkbox)數據。
  • String getParameter(String name)
    根據指定的請求參數名稱,獲取其對應的值。若該參數名稱對應的是多個值,則該方法獲取到的是第一個值。這個方法是最常用的方法。

獲取客戶端信息的方法:

    • getRequestURL方法返回客戶端發出請求時的完整URL。
    • getRequestURI方法返回請求行中的資源名部分。
    • getQueryString 方法返回請求行中的參數部分。
    • getRemoteAddr方法返回發出請求的客戶機的IP地址
    • getRemoteHost方法返回發出請求的客戶機的完整主機名
    • getRemotePort方法返回客戶機所使用的網絡端口號
    • getLocalAddr方法返回WEB服務器的IP地址。
    • getLocalName方法返回WEB服務器的主機名
    • getMethod得到客戶機請求方式
       1 /**
       2  * HttpServletRequest獲取請求數據
       3  */
       4 public class RequestTest01 extends HttpServlet {
       5     private static final long serialVersionUID = 1L;
       6 
       7     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       8         //根據html中的name的名字獲取用戶在input中填寫的值
       9         String username = request.getParameter("username");
      10         String password = request.getParameter("password");
      11         //獲取用戶勾選的checkbox的值
      12         String[] hobby = request.getParameterValues("hobby");
      13 
      14         System.out.println(username);
      15         System.out.println(password);
      16         for(String s:hobby){
      17             System.out.println(s);
      18         }
      19     }
      20 
      21     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      22         doGet(request, response);
      23     }
      24 
      25 }

      亂碼的產生原因

      當用戶通過瀏覽器提交一個包含 UTF-8 編碼格式的兩個中文請求時,瀏覽器會將這兩個中文字符變為六個字節(一般一個 UTF-8 漢字占用三個字節),即形成六個類似%8E 的字節表示形式,並將這六個字節上傳至 Tomcat 服務器。
      Tomcat 服務器在接收到這六個字節后,並不知道它們原始采用的是什么字符編碼。而Tomcat 默認的編碼格式為 ISO-8859-1。所以會將這六個字節按照 ISO-8859-1 的格式進行解碼,解碼后在控制台顯示,所以在控制台會顯示亂碼。

      亂碼的解決方案

      針對 POST 提交亂碼的解決方式
      在接收請求參數之前先通過 request 的 setCharacterEncoding()方法,指定請求體的字符編碼格式。這樣的話,在接收到請求中的參數后,就可按照指定的字符編碼進行解碼。
      注意,request 的 setCharacterEncoding()方法只能解決 POST 提交方式中的亂碼問題,對
      於 GET 提交方式的不起作用。因為該方法設置的是請求體中的字符編碼, GET 提交中的參數不出現在請求體中,而出現在請求行。

    •  1     //設置post請求的字符編碼
       2     request.setCharacterEncoding("utf-8");
       3 
       4     //根據html中的name的名字獲取用戶在input中填寫的值
       5     String username = request.getParameter("username");
       6     String password = request.getParameter("password");
       7     //獲取用戶勾選的checkbox的值
       8     String[] hobby = request.getParameterValues("hobby");
       9 
      10     System.out.println(username);
      11     System.out.println(password);
      12     for(String s:hobby){
      13         System.out.println(s);
      14     }

      針對get提交亂碼的解決方式
      可以通過修改 Tomcat 默認字符編碼的方式來解決 GET 提交方式中攜帶中文的亂碼問題。在 Tomcat 安裝目錄的 conf/server.xml 中,找到端口號為 8080 的標簽,在其中添加 URIEncoding=”UTF-8″的設置,即可將 Tomcat 默認字符編碼修改為 UTF-8。

       <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/> 

      需要注意的是在修改時要找到正確的server.xml文件。
      雙擊tomcat服務器,如下圖:

      設置tomcat的路徑

      上圖中有三個選項,不同的選項表示使用的不同路徑下的tomcat

      1. 表示使用eclipse工作空間的tomcat,該路徑在工作空間目錄中的.metadata.plugins\org.eclipse.wst.server.core\tmp0目錄中,如果你使用的是這個(eclipse會默認使用這個),需要修改該目錄中的server.xml才會生效。
      2. 表示使用我單獨下載的tomcat所在的路徑,我本機的是在:F:\monkey1024\apache-tomcat-9.0.0.M26中,如果你使用的是這個,需要修改該目錄中的server.xml文件。
      3. 表示自定義一個位置,即手動指定web應用運行的目錄位置,如果你使用的是這個,需要修改該目錄中的server.xml文件。

      萬能解決方案

      1 //根據html中的name的名字獲取用戶在input中填寫的值
      2 String username = request.getParameter("username");
      3 //將數據按照ISO8859-1編碼后放到字節數組中
      4 byte[] bytes = username.getBytes("ISO8859-1");
      5 //將字節數組按照UTF-8解碼為字符串
      6 username = new String(bytes,"UTF-8");

      先以 ISO8859-1 的形式先對單字節的數據進行編碼,並將編碼后的數據存放在字節數組中。然

      后,再將字節數組中的數據,按照指定的 UTF-8 格式進行解碼,即變為了需要的 UTF-8 字符
      編碼的數據,解決了中文亂碼問題。
      通過上面的代碼就可以解決get和post的亂碼問題,但是代碼量較大,開發中使用較少。

 

HttpServletResponse簡介

Web服務器收到客戶端的http請求,會針對每一次請求,創建一個用於代表響應的HttpServletResponse類型的response對象,開發者可以將要向客戶端返回的數據封裝到response對象中。

HttpServletResponse向客戶端發送數據

ServletResponse 接口有一個方法 getWriter(),用於獲取到一個輸出流對象 PrintWriter,
該輸出流對象是專門用於向客戶端瀏覽器中輸出字符數據的,稱為標准輸出流。

package com.monkey1024.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 使用HttpServletResponse向客戶端發送數據 * */ public class ResponseTest01 extends HttpServlet { private static final long serialVersionUID = 1L; 
 1     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2         //設置post請求的字符編碼,此方式只對post請求有效
 3         request.setCharacterEncoding("UTF-8");
 4         //根據html中的name的名字獲取用戶在input中填寫的value值
 5         String username = request.getParameter("username");
 6 
 7         //從response中取得PrintWriter對象
 8         PrintWriter out = response.getWriter();
 9         //向客戶端發送數據
10         out.print("用戶:" + username + "添加成功!<br>");
11         out.print("感謝您的注冊");
12         //關閉PrintWriter
13         out.close();
14     }
15     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
16         doGet(request, response);
17     }
18 
19 }

 

HttpServletResponse響應亂碼的解決方案

響應時會產生亂碼的原因是在 HTTP 協議中規定,默認響應體的字符編碼為ISO-8859-1。所以,若要解決亂碼問題,就需要修改響應體的默認編碼。一般情況下,有兩種方式可以修改:

  • 方法一:HttpServletResponse 的 setCharacterEncoding(“utf-8”)方法,將編碼修改為utf-8,然后再通過setHead(“Content-type”,”text/html;charset=UTF-8″);方法告訴客戶端瀏覽器的編碼方式。
    代碼:

     

    1   response.setCharacterEncoding("UTF-8");
    2   response.setHead("Content-type","text/html;charset=UTF-8");

     

  • 方法二:為了簡便操作,開發者可以直接使用HttpServletResponse 的 setContentType(“text/html;charset=utf-8”)方法,告訴瀏覽器的編碼方式,該方法相當於方法一種的兩條代碼。
    代碼:
    1 response. setContentType("text/html;charset=UTF-8");

注意:設置響應編碼時必須在 PrintWriter 對象產生之前先設置,否則將不起作用。

 

轉發:

 1 /**
 2  * 轉發
 3  */
 4 public class Forward01 extends HttpServlet {
 5     private static final long serialVersionUID = 1L;
 6 
 7     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 8         //設置字符編碼
 9         request.setCharacterEncoding("UTF-8");
10         //獲取請求參數
11         String username = request.getParameter("username");
12         String password = request.getParameter("password");
13 
14         request.setAttribute("username", username);
15         request.setAttribute("password", password);
16 
17         //轉發
18         request.getRequestDispatcher("Other").forward(request, response);
19     }
20 
21     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
22         doGet(request, response);
23     }
24 
25 }

 

重定向:

 1 /**
 2  * 重定向
 3  */
 4 public class Redirect01 extends HttpServlet {
 5     private static final long serialVersionUID = 1L;
 6 
 7     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 8         //設置字符編碼
 9         request.setCharacterEncoding("UTF-8");
10         //獲取請求參數
11         String username = request.getParameter("username");
12         String password = request.getParameter("password");
13 
14         request.setAttribute("username", username);
15         request.setAttribute("password", password);
16 
17         //重定向到上面的Other servlet中
18         response.sendRedirect("Other");
19     }
20 
21     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
22         doGet(request, response);
23     }
24 
25 }

 

當點擊之后注意瀏覽器地址欄中的url是會發生變化的,url后面請求的路徑變為了Other。

如果想要重定向到另外一個項目的servlet上時,只需要在sendRedirect加上項目的訪問名:

1 response.sendRedirect("/other-app/Other");

其中other-app是另外項目的訪問名。

 

轉發和重定向的區別

  • 請求轉發
    1. 瀏覽器只發出一次請求,收到一次響應
    2. 請求所轉發到的servlet2中可以直接獲取到請求中所攜帶的數據
    3. 瀏覽器地址欄顯示的為用戶所提交的請求路徑
    4. 只能跳轉到當前應用的資源中
  • 重定向
    1. 瀏覽器發出兩次請求,接收到兩次響應
    2. 重定向到的servlet2不能直接獲取到用戶提交請求中所攜帶的數據
    3. 瀏覽器地址欄顯示的為重定向的請求路徑,而非用戶提交請求的路徑。也正因為如此,重定向的一個很重要作用是:防止表單重復提交
    4. 重定向不僅可以跳轉到當前應用的其它資源,也可以跳轉到到其它應用中資源

請求轉發與重定向的選擇

  • 若需要跳轉到其它應用,則使用重定向。
  • 若是處理表單數據的Servlet1要跳轉到另外的Servlet2上,則需要選擇重定向。為了防止表單重復提交。
  • 若對某一請求進行處理的 Servlet 的執行需要消耗大量的服務器資源(CPU、內存),此時這個 Servlet 執行完畢后,也需要重定向。
  • 其它情況,一般使用請求轉發。


免責聲明!

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



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