java基礎學習:JavaWeb之request和response

Hiway發表於2018-12-16

其他更多java基礎文章: java基礎學習(目錄)

學習request和response之前先學習一下http請求


HTTP請求

瀏覽器向伺服器請求某個web資源時,稱之為瀏覽器向伺服器傳送了一個http請求。一個完整http請求應該包含三個部分:

  • 請求行【描述客戶端的請求方式、請求的資源名稱,以及使用的HTTP協議版本號】
  • 多個訊息頭【描述客戶端請求哪臺主機,以及客戶端的一些環境資訊等】
  • 一個空行

請求行

請求行:GET /java.html HTTP/1.1 請求行中的GET稱之為請求方式,
請求方式有:POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT。
常用的有:POST,GET
一般來說,當我們點選超連結,通過位址列訪問都是get請求方式。通過表單提交的資料一般是post方式。
可以簡單理解GET方式用來查詢資料,POST方式用來提交資料,get的提交速度比post快
GET方式:在URL地址後附帶的引數是有限制的,其資料容量通常不能超過1K。
POST方式:可以在請求的實體內容中向伺服器傳送資料,傳送的資料量無限制。

請求頭

  • Accept: text/html,image/* 【瀏覽器告訴伺服器,它支援的資料型別】
  • Accept-Charset: ISO-8859-1 【瀏覽器告訴伺服器,它支援哪種字符集
  • Accept-Encoding: gzip,compress 【瀏覽器告訴伺服器,它支援的壓縮格式
  • Accept-Language: en-us,zh-cn 【瀏覽器告訴伺服器,它的語言環境】
  • Host: www.it315.org:80【瀏覽器告訴伺服器,它的想訪問哪臺主機】
  • If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT【瀏覽器告訴伺服器,快取資料的時間】
  • Referer: www.it315.org/index.jsp【瀏覽器告訴伺服器,客戶機是從那個頁面來的---反盜鏈
  • 8.User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)【瀏覽器告訴伺服器,瀏覽器的核心是什麼】
  • Cookie【瀏覽器告訴伺服器,帶來的Cookie是什麼
  • Connection: close/Keep-Alive 【瀏覽器告訴伺服器,請求完後是斷開連結還是保持連結】
  • Date: Tue, 11 Jul 2000 18:23:51 GMT【瀏覽器告訴伺服器,請求的時間】

HTTP響應

一個HTTP響應代表著伺服器向瀏覽器回送資料,一個完整的HTTP響應應該包含四個部分:

  1. 一個狀態行【用於描述伺服器對請求的處理結果。
  2. 多個訊息頭【用於描述伺服器的基本資訊,以及資料的描述伺服器通過這些資料的描述資訊,可以通知客戶端如何處理等一會兒它回送的資料
  3. 一個空行
  4. 實體內容【伺服器向客戶端回送的資料

狀態行

格式: HTTP版本號 狀態碼 原因敘述 狀態行:HTTP/1.1 200 OK 狀態碼用於表示伺服器對請求的處理結果,它是一個三位的十進位制數。響應狀態碼分為5類

image.png

響應頭

  • Location: www.it315.org/index.jsp 【伺服器告訴瀏覽器要跳轉到哪個頁面
  • Server:apache tomcat【伺服器告訴瀏覽器,伺服器的型號是什麼】
  • Content-Encoding: gzip 【伺服器告訴瀏覽器資料壓縮的格式
  • Content-Length: 80 【伺服器告訴瀏覽器回送資料的長度】
  • Content-Language: zh-cn 【伺服器告訴瀏覽器,伺服器的語言環境】
  • Content-Type: text/html; charset=GB2312 【伺服器告訴瀏覽器,回送資料的型別
  • Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT【伺服器告訴瀏覽器該資源上次更新時間】
  • Refresh: 1;url=www.it315.org【伺服器告訴瀏覽器要定時重新整理
  • Content-Disposition: attachment; filename=aaa.zip【伺服器告訴瀏覽器以下載方式開啟資料
  • Transfer-Encoding: chunked 【伺服器告訴瀏覽器資料以分塊方式回送】
  • Set-Cookie:SS=Q0=5Lb_nQ; path=/search【伺服器告訴瀏覽器要儲存Cookie
  • Expires: -1【伺服器告訴瀏覽器不要設定快取
  • Cache-Control: no-cache 【伺服器告訴瀏覽器不要設定快取
  • Pragma: no-cache 【伺服器告訴瀏覽器不要設定快取
  • Connection: close/Keep-Alive 【伺服器告訴瀏覽器連線方式】
  • Date: Tue, 11 Jul 2000 18:23:51 GMT【伺服器告訴瀏覽器回送資料的時間】

HttpServletRequest

概述

HttpServletRequest物件代表客戶端的請求,當客戶端通過HTTP協議訪問伺服器時,HTTP請求頭中的所有資訊都封裝在這個物件中,開發人員通過這個物件的方法,可以獲得客戶這些資訊。 request就是將請求文字封裝而成的物件,所以通過request能獲得請求文字中的所有內容,請求頭、請求體、請求行

image.png

常用方法

1. 請求頭

  我們可以檢視任意一個網頁,它都是有請求頭的。

  

image

相關方法:
String getHeader(String name) 根據頭名稱得到頭資訊值
long getDateHeader(java.lang.String name) 獲得指定頭內容Date
int getIntHeader(java.lang.String name) 獲得指定頭內容int
Enumeration getHeaderNames() 得到所有頭資訊name
Enumeration getHeaders(String name) 根據頭名稱得到相同名稱頭資訊值

Enumeration<String> headerNames = req.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String key = (String)headerNames.nextElement();
            String value = req.getHeader(key);
            System.out.println(key+"="+value);
        } 
複製程式碼
2. 請求體

1)與表單獲取相關的方法:
String getParameter(name) :根據表單中name屬性的名,獲取value屬性的值方法
String[] getParameterValues(String name):專為核取方塊取取提供的方法
getParameterNames():得到表單提交的所有name的方法
Map<String , String[]> getParameterMap(): 得到表單提交的所有值的方法 //做框架用,非常實用
getInputStream: 以位元組流的方式得到所有表單資料

2)與操作非表單資料相關的方法(request也是一個域物件):
void setAttribute(String name, Object value);
Object getAttribute(String name);
Void removeAttribute(String name);

3)與請求轉發相關的方法:
RequestDispatcher getRequestDispatcher(String path) //得到請求轉發或請求包含的協助物件
forward(ServletRequest request, ServletResponse response) //轉發的方法
include(ServletRequest request, ServletResponse response) //請求包含

4)與編碼相關的方法:
//解決post方式編碼
request.setCharacterEncoding("UTF-8") :告訴伺服器客戶端什麼編碼,只能處理post請求方式
//解決get方式編碼
String name = new String(name.getBytes(“iso-8859-1”),”UTF-8”);

#####3. 其他常用請求方法
getMethod();
getRequestURL();
getRequestURI();
getServerName();
getServerPort();
getContextPath();
getServletPath();
getQueryString();
getRemoteAddr();
getProtocol();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.統一資源標記符   /Web_Servlet/ServletTest3
        String uri = req.getRequestURI();
        System.out.println(uri);
        //2.統一資源定位符    http://localhost:6060/Web_Servlet/ServletTest3 
        StringBuffer url = req.getRequestURL();
        System.out.println(url);
        //3.協議和版本    HTTP/1.1
        String potocol = req.getProtocol();
        System.out.println(potocol);
        //4.協議    http
        String scheme = req.getScheme();
        System.out.println(scheme);
        //5.主機(域名)  localhost,如果你使用的是ip地址,就顯示ip地址
        String serverName = req.getServerName();
        System.out.println(serverName);
        //6.埠  6060(這是我自己修改了的埠,預設是8080)
        int port = req.    getServerPort();
        System.out.println(port);
        //7.釋出到tomcat下的專案名稱  /Web_Servlet
        String contextPath = req.getContextPath();
        System.out.println(contextPath);
        //8.servlet路徑    /ServletTest3 
        String servletPath = req.getServletPath();
        System.out.println(servletPath);
        //9.獲取所有請求引數,即?之後所有東西。    username=faker&password=mid
        String queryString = req.getQueryString();
        System.out.println(queryString);
        //10.遠端主機的ip地址    0:0:0:0:0:0:0:1
        String remoteAddr = req.getRemoteAddr();
        System.out.println(remoteAddr);   
    }
複製程式碼

HttpServletResponse

概述

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

  

image

常用方法

響應行\響應頭\響應體

setStatus(int sc) 設定響應狀態碼
setHeader(String name, String value) 設定響應頭資訊
getWrite(); 字元輸出流
getOutputStream(); 位元組輸出流
setCharacterEncoding(String charset) 告知伺服器使用什麼編碼
setContentType(String type) 告訴響應的內容型別(text/html,application/json等)

重定向

response.sendRedirect(path);
注意:重定向沒有任何侷限,可以重定向web專案內的任何路徑,也可以訪問別的web專案中的路徑,並且這裡就用"/"區分開來,如果path使用了"/"開頭,就說明我要重新開始定位了,不訪問剛才的web專案,自己寫專案名,如果path沒有使用"/"開始,那麼就知道是訪問剛才那個web專案下的servlet,就可以省略專案名了。就是這樣來區別。

兩者的細節

兩種setCharacterEncoding

  1. request.setCharacterEncoding()指定後可以通過getParameter()則直接獲得正確的字串,如果不指定,則預設使用iso8859-1編碼。值得注意的是在執行setCharacterEncoding()之前,不能執行任何getParameter()。而且,該指定只對POST方法有效,對GET方法無效。
    分析原因,應該是在執行第一個getParameter()的時候,Java將會按照編碼分析所有的提交內容,而後續的getParameter()不再進行分析,所以setCharacterEncoding()無效。而對於GET方法提交表單是,提交的內容在URL中,一開始就已經按照編碼分析提交內容,setCharacterEncoding()自然就無效。

  2. response.setCharacterEncoding設定HTTP 響應的編碼,如果之前使用response.setContentType設定了編碼格式,則使用response.setCharacterEncoding指定的編碼格式覆蓋之前的設定.與response.setContentType相同的是,呼叫此方法,必須在getWriter執行之前或者response被提交之前

學習資料:www.cnblogs.com/fan-xiaofan…

轉發與重定向

實際發生位置不同,位址列不同

轉發是發生在伺服器的:
轉發是由伺服器進行跳轉的,細心的朋友會發現,在轉發的時候,瀏覽器的位址列是沒有發生變化的,在我訪問Servlet111的時候,即使跳轉到了Servlet222的頁面,瀏覽器的地址還是Servlet111的。也就是說瀏覽器是不知道該跳轉的動作,轉發是對瀏覽器透明的。通過上面的轉發時序圖我們也可以發現,實現轉發只是一次的http請求,一次轉發中request和response物件都是同一個。這也解釋了,為什麼可以使用request作為域物件進行Servlet之間的通訊。

重定向是發生在瀏覽器的:
重定向是由瀏覽器進行跳轉的,進行重定向跳轉的時候,瀏覽器的地址會發生變化的。曾經介紹過:實現重定向的原理是由response的狀態碼和Location頭組合而實現的。這是由瀏覽器進行的頁面跳轉實現重定向會發出兩個http請求,request域物件是無效的,因為它不是同一個request物件

用法不同

很多人都搞不清楚轉發和重定向的時候,資源地址究竟怎麼寫。有的時候要把應用名寫上,有的時候不用把應用名寫上。很容易把人搞暈。記住一個原則:給伺服器用的直接從資源名開始寫,給瀏覽器用的要把應用名寫上

request.getRequestDispatcher("/資源名 URI").forward(request,response)
轉發時"/"代表的是本應用程式的根目錄

response.send("/web應用/資源名 URI");
重定向時"/"代表的是webapps目錄

能夠去往的URL的範圍不一樣

轉發是伺服器跳轉只能去往當前web應用的資源
重定向是伺服器跳轉,可以去往任何的資源

傳遞資料的型別不同

轉發的request物件可以傳遞各種型別的資料,包括物件
重定向只能傳遞字串

跳轉的時間不同

轉發時:執行到跳轉語句時就會立刻跳轉
重定向:整個頁面執行完之後才執行跳轉

Servlet中亂碼解決與轉發和重定向的區別

getWriter和getOutputStream

1.選擇getOutputStream 和getWriter方法的要點

PrintWriter物件輸出字元文字內容時,它內部還是將字串轉換成了某種字符集編碼的位元組陣列後再進行輸出,使用PrintWriter物件的好處就是不用程式設計人員自己來完成字串到位元組陣列的轉換。
使用ServletOutputStream物件也能輸出內容全為文字字元的網頁文件,但是,如果網頁文件內容是在Servlet程式內部使用文字字串動態拼湊和建立出來的,則需要先將字元文字轉換成位元組陣列後輸出。

2.兩種方法區別

getOutputStream方法用於返回Servlet引擎建立的位元組輸出流物件,Servlet程式可以按位元組形式輸出響應正文。
getWriter方法用於返回Servlet引擎建立的字元輸出流物件,Servlet程式可以按字元形式輸出響應正文。
getOutputStream和getWriter這兩個方法互相排斥,呼叫了其中的任何一個方法後,就不能再呼叫另一方法。
getOutputStream方法返回的位元組輸出流物件的型別為ServletOutputStream,它可以直接輸出位元組陣列中的二進位制資料。
getWriter方法將Servlet引擎的資料緩衝區包裝成PrintWriter型別的字元輸出流物件後返回,PrintWriter物件可以直接輸出字元文字內容。
Servlet程式向ServletOutputStream或PrintWriter物件中寫入的資料將被Servlet引擎獲取,Servlet引擎將這些資料當作響應訊息的正文,然後再與響應狀態行和各響應頭組合後輸出到客戶端。
Serlvet的service方法結束後,Servlet引擎將檢查getWriter或getOutputStream方法返回的輸出流物件是否已經呼叫過close方法,如果沒有,Servlet引擎將呼叫close方法關閉該輸出流物件。

3.修改編碼型別

getOutputStream解決辦法:

  1. 通過更改瀏覽器的編碼方式:IE/”檢視”/”編碼”/”UTF-8”(不可取)
  2. 通過設定響應頭告知客戶端編碼方式:response.setHeader(“Content-type”, “text/html;charset=UTF-8”);//告知瀏覽器資料型別及編碼
  3. 通過meta標籤模擬請求頭:out.write("".getBytes());
  4. 通過以下方法:response.setContentType("text/html;charset=UTF-8");

rgetWriter解決辦法:
response. setContentType(“text/html;charset=UTF-8”);

兩者的應用

1. 檔案下載
        //通過路徑得到一個輸入流
        String path = this.getServletContext().getRealPath(filepath);
        FileInputStream fis = new FileInputStream(path);
        //建立位元組輸出流
        ServletOutputStream sos = response.getOutputStream();
        
        //得到要下載的檔名
        String filename = path.substring(path.lastIndexOf("\\")+1);
        
        //設定檔名的編碼
        filename = URLEncoder.encode(filename, "UTF-8");//將不安全的檔名改為UTF-8格式
        
        //告知客戶端要下載檔案
        response.setHeader("content-disposition", "attachment;filename="+filename);
        response.setHeader("content-type", "image/jpeg");
        
        //執行輸出操作
        int len = 1;
        byte[] b = new byte[1024];
        while((len=fis.read(b))!=-1){
            sos.write(b,0,len);
        }
        
        sos.close();
        fis.close();

複製程式碼
2. 驗證碼
3. 定時重新整理
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("3秒後跳轉頁面.....");
        //三秒後跳轉到index.jsp頁面去
        response.setHeader("Refresh", "3;url='/index.jsp'");
複製程式碼
4. 設定快取
        //瀏覽器有三訊息頭設定快取,為了相容性!將三個訊息頭都設定了
        response.setDateHeader("Expires", -1);
        response.setHeader("Cache-Control","no-cache");
        response.setHeader("Pragma", "no-cache");
複製程式碼
5. 資料壓縮
       //建立GZIPOutputStream物件,給予它ByteArrayOutputStream
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);

        //GZIP對資料壓縮,GZIP寫入的資料是儲存在byteArrayOutputStream上的
        gzipOutputStream.write("asdfzxcvasdfzxvasdfzxcv".getBytes());
        //gzipOutputStream有緩衝,把緩衝清了,並順便關閉流
        gzipOutputStream.close();

        byte[] bytes = byteArrayOutputStream.toByteArray();
        //告訴瀏覽器這是gzip壓縮的資料
        response.setHeader("Content-Encoding","gzip");
        //將壓縮的資料寫給瀏覽器
        response.getOutputStream().write(bytes);
複製程式碼
6. 防盜鏈
        //獲取到網頁是從哪裡來的
        String referer = request.getHeader("Referer");
複製程式碼

相關文章