WEB開發2--request&response

shuaishuai3409發表於2016-10-01

Web伺服器收到客戶端的http請求,會針對每一次請求,分別建立一個用於代表請求的request物件、和代表響應的response物件。request和response物件即然代表請求和響應,那我們要獲取客戶機提交過來的資料,只需要找request物件就行了。要向容器輸出資料,只需要找response物件就行了。


一 Response

1 常見方法
Response分為響應訊息行,響應訊息頭和響應正文。對應Request分為請求訊息行,請求訊息頭和請求正文。主要呼叫ServletResponse和HttpServletResponse類(介面)裡的方法

這裡寫圖片描述


2 常見作用

2.1 向客戶端傳送中文資料(解決亂碼問題)

  • 以字元流的形式響應(字串文字資料)
    response.getWriter().write(“中國”);//getWriter()返回Printwriter物件

接連出現??涓浗的問題,原因如下:

由於Tomcat伺服器中預設編碼方式為ISO-8859-1,不支援中文。本身解析不了“中國“,所以在向瀏覽器響應結果時,出現??無法識別的情況(不是亂碼),方法:setCharacterEncoding(“UTF-8”),告知伺服器用UTF-8的方式解析文字。
然後,重新部署後,再次向瀏覽器響應結果時是“涓浗”(亂碼),原因是沒有告知瀏覽器應該用UTF-8的方式編碼,方法:response.setHeader(“content-type”, “text/html;charset=UTF-8”)。

其實有個更簡單的方法,直接告知伺服器和瀏覽器均用UTF-8的方式編碼,當然也可以用別的編碼方式,格式:response. setContentType(“text/html;charset=UTF-8”);

  • 以位元組流的形式響應(二進位制)

response.getOutputStream().write(“中國”.getByte());//以預設編碼傳送資料;getOutputStream()返回ServletOuputStream物件。

getByte(): String類中的方法,返回byte[];使用平臺的預設字符集將此 String 編碼為 byte 序列,並將結果儲存到一個新的 byte 陣列中。(預設字符集就是你在安裝作業系統時選擇的安裝語言,簡體中文的編碼方式是GBK)。

response.getOutputStream().write(“中國”.getByte(“UTF-8”));//以UTF-8編碼向客戶端傳送資料,若瀏覽器預設GBK,會出現亂碼(不一致而導致的亂碼)。所以這時需要response.setContentType(“text/html;charset=UTF-8”);告知瀏覽器一聲用UTF-8編碼。

例項:
當response.setContentType(“text/html;charset=UTF-8”);
response.getOutputStream().write(“中國”.getByte());共同使用時,由於位元組輸出流使用預設編碼(中文–GBK),不一致就會出現亂碼。

注意:getOutputStream和getWriter這兩個方法互相排斥,呼叫了其中的任何一個方法後,就不能再呼叫另一方法,否則會拋異常。


2.2 實現請求重定向

定義:一個web資源收到客戶端請求後,(可能由於自身無法處理等問題)通知客戶端去訪問另外一個web資源,這稱之為請求重定向。

特點:位址列會變,併傳送2次請求。

實現方式:
response.sendRedirect()

實現原理:
302/307狀態碼和location頭即可實現重定

注意:sendRedirect的路徑引數寫法,是絕對路徑還是相對路徑(帶不帶”/”)?要不要寫上應用名(專案名)?如果引數為”www.baidu.com“,允許這樣寫嗎?會發生什麼?要與後面的Request的請求轉發方法RequestDispatcher()引數區分開。

response.sendRedirect("/day01/ResponseDemo4");//注意重定向時,不一定定向到哪個專案裡去了,故需要在引號裡寫上/+專案名(應用名)。表示http//localhost:8080/後面的東西。當然也可以直接寫"www.baidu.com",會跳轉到百度介面

//sendRedirect本質上是下面方式的合併:

response.setStatus(302);//307也可以,都是告訴客戶端要重新定向新的資源

response.setHeader("location", "/day01/ResponseDemo4");//傳送響應訊息頭,告訴瀏覽器要去訪問哪個URL。

3 Response重定向執行過程細節

重定向

  1. 客戶端傳送http請求給web伺服器
  2. 若是首次訪問,web伺服器建立servlet(例項化,初始化);若不是,往下走(客戶端訪問同一個servlet,只初始化,例項化一次)。
  3. web伺服器建立request和response物件。(初始時請求資訊是有客戶端傳來的資料的,響應資訊是空的)
  4. web伺服器呼叫servlet的service(req,rep)方法。
  5. web把執行權交給servlet,先通過request獲取請求資訊(頭,行,正文)。
  6. 然後執行程式,用sendRedirect方法,寫特殊響應頭,將結果儲存到response物件中()
  7. servlet的service方法執行完畢,將執行權返回給web伺服器。
  8. web伺服器解析response物件返回值,發出包含重定向的http響應,返回給客戶端。(web伺服器=tomcat=servlet引擎)
  9. 客戶端傳送包含重定向的請求資訊
  10. 然後又是一個輪迴,只不過不用再建立servlet,而且執行權在servlet時,不用寫特殊響應頭,而是寫真正的返回結果;另外web伺服器返回不返回包含重定向的http響應,而是返回真正的結果。

二 Request

1 常用方法及含義
這裡寫圖片描述

2 獲取表單資料(Form)中文亂碼問題

方法一:request.getParameter(name);

public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        String[] hobbys = request.getParameterValues("hobby");
        System.out.println(username);
        for(int i=0;i<hobbys.length;i++){
        System.out.println(hobbys[i]);
        }
    }
方法二:request.getParameterNames()

private void doGet(HttpServletRequest request)
            throws UnsupportedEncodingException {
        request.setCharacterEncoding("UTF-8");
        Enumeration names = request.getParameterNames();
        while(names.hasMoreElements()){
            String name = (String)names.nextElement();
            String values[]=request.getParameterValues(name);
            for(int i=0;values!=null&&i<values.length;i++){
                System.out.println(values[i]);
            }
        }
    }
方法三:getParameterMap()
public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                try {
                User u=new User();
                Map <String,String[]> map=request.getParameterMap();

                for(Map.Entry<String,String[]> m: map.entrySet()){
                    String key=m.getKey();
                    String value[]=m.getValue();
                    PropertyDescriptor pd=new PropertyDescriptor(key,User.class);//
                    Method setter=pd.getWriteMethod();
                    if(value.length==1){
                        setter.invoke(key, value[0]);
                    }
                    else{
                        setter.invoke(key, (Object)value);
                    }
                }
        } catch (Exception e) {
                e.printStackTrace();
            }
    }


3 請求轉發

客戶端傳送請求後,伺服器一個servlet無法完全處理,需要和另一個servlet協作,兩者返回的結果共同響應給客戶端。使用request.RequestDispatcher()方法,設定路徑引數時要注意必須是絕對路徑,而且只能是當前應用的servlet(類)。
這裡寫圖片描述

  1. 客戶端傳送http請求
  2. 若是首次訪問,servlet引擎例項化並初始化servlet,若不是直接到3
  3. servlet引擎建立請求request和響應response物件。
  4. servlet引擎呼叫service(req,rep)方法,傳入剛建立的兩個物件作為引數
  5. servlet引擎將執行權交給servlet,呼叫service裡的doGet方法,獲取請求資訊
  6. servlet呼叫service方法中的doPost方法,寫入響應資訊
  7. servlet向servlet引擎返回請求轉發forward命令(只能轉發當前應用下的其他servlet、jsp等)
  8. servlet引擎收到forward命令後,找到請求轉發地址(URI/Mapping),若是第一次訪問,建立servlet2,並呼叫servlet2的service方法。
  9. servlet2讀取請求資訊
  10. 在原來響應資訊基礎上,追加資訊的響應資訊
  11. serlet2的service方法返回
  12. servlet的service方法返回
  13. servlet引擎解析響應資訊
  14. servlet引擎返回響應結果給客戶端

3.1 請求轉發與重定向的區別

轉發:位址列不變;客戶端只請求一次;servlet間可以傳遞資料;不可以跳轉到其他應用。
重定向:位址列變;客戶端請求兩次;不可以傳遞資料;可以跳轉到其他應用。


4 請求包含

包含:Servelt(源元件)把其他web元件(目標元件)生成的響應結果包含到自身的響應結果中。

轉發和請求包含的共同點
源元件和目標元件處理的都是同一個客戶請求,源元件和目標元件共享同一個ServeltRequest和ServletResponse物件。
目標元件都可以為Servlet、JSP或HTML文件
都依賴 javax.servlet.RequestDispatcher介面