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");