web客戶端發送給web服務器的HTTP請求消息能夠分爲三個部分:請求行、請求消息頭、消息正文(也叫實體內容)。Servlet程序經過調用ServletRequest對象的方法能夠獲知客戶端的請求信息,以及客戶機和服務器的網絡環境信息,例如獲取客戶發送的請求消息的各個部分和客戶端IP地址。HttpServletRequest是專用於HTTP協議的ServletRequest子接口,它用於封裝HTTP請求消息,增長了獲取HTTP協議專有的頭信息的方法,以及獲取HTTP請求消息參數的功能。html
HTTP請求消息的請求行能夠分爲三個部分:請求方式、資源路徑和HTTP協議版本,如:java
GET /project/servlet/RequestURI?parm1=a&parm2=b HTTP/1.1web
RequestLineServlet.java數組
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; public class RequestLineServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=GB2312"); PrintWriter out = response.getWriter(); out.println("getMethod:" + request.getMethod() + "<br>"); // 返回位於主機和端口以後、參數部分以前的那部份內容 out.println("getRequestURI:" + request.getRequestURI() + "<br>"); // 返回參數部分,無參數返回null out.println("getQueryString:" + request.getQueryString() + "<br>"); // 返回協議名和版本號 out.println("getProtocol:" + request.getProtocol() + "<br>"); // 返回Web應用程序的路徑(虛擬目錄),這個路徑以「/」開頭 out.println("getContextPath:" + request.getContextPath() + "<br>"); // 返回servlet映射的路徑(web.xml的url-pattern屬性) out.println("getServletPath:" + request.getServletPath() + "<br>"); } }
注:URL和URI的區別,可看http://www.cnblogs.com/gaojing/archive/2012/02/04/2413626.html瀏覽器
ServletRequest和HttpServletRequest接口中定義了若干用於讀取HTTP請求消息中的頭字段的方法,其中的getHeader方法是一個通用的方法,能夠讀取全部的頭字段。服務器
(1)、獲取全部請求頭信息網絡
RequestHeadersServlet.javaapp
import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class RequestHeadersServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=GB2312"); PrintWriter out = response.getWriter(); Enumeration<?> headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String headerName = (String)headerNames.nextElement(); // 同一個請求頭名可能出現屢次 Enumeration<?> values = request.getHeaders(headerName); while(values.hasMoreElements()) { out.println(headerName + ":" + (String)values.nextElement() + "<br>"); } } } }
在瀏覽器輸入訪問地址:http://localhost:8888/requestHeadersServlet/servlet/RequestHeadersServletide
現增長一個html文件,從它連接到該Servlet,訪問referer.html:編碼
<a href="servlet/RequestHeadersServlet">referer test</a>
訪問referer.html:
點擊超連接,再次訪問RequestHeadersServlet
注意觀察:請求消息包含了referer請求頭。
(2)盜鏈
關於「盜鏈」:http://baike.baidu.com/link?url=UpFE0AJdwVL2ESHqD6aF1N28Zmwi47RwoKzs50NI2t1HKBR6paci_NFhbv78hW-x
爲了防止「盜鏈」,須要檢查請求的來路,只接受本站內的頁面連接進來的下載請求,而阻止其餘站點的頁面連接進來的下載請求。要實現這樣功能,就須要檢查請求消息的referer頭字段是否與本站匹配。
DownManagerServlet.java
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; public class DownManagerServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=GB2312"); String referer = request.getHeader("referer"); String sitePart = "http://" + request.getServerName(); PrintWriter out = response.getWriter(); // 增長if判斷是爲了下載請求必須經過本站的下載頁面連接進來,也就是防止盜鏈 if(referer != null && referer.startsWith(sitePart)) { // 處理正當的下載請求,這裏只是示意 out.println("dealing download ..."); } else { // 非法下載請求(即referer爲空或不匹配sitePart)跳轉到本站的下載說明頁 response.sendRedirect("../down.html"); } } }
down.html
<a href="servlet/DownManagerServlet">down</a>
在瀏覽器輸入訪問地址:localhost:8888/downManagerServlet/servlet/DownManagerServlet
由於請求消息不含referer請求頭,即DownManagerServlet代碼中的referer爲空,跳轉到down.html
點擊超連接,再次訪問DownManagerServlet,因爲這時的請求消息包含有referer請求且值與DownManagerServlet位於同一Web站點,DownManagerServlet接受下載請求。
以POST方式提交HTML的FORM表單時,其中的表單字段元素信息都將做爲HTTP消息的實體內容(消息正文)發送給Web服務器。對應HTTP請求消息的中的實體內容,ServletRequest以輸入流的方式提供給Servlet程序讀取,ServletRequest接口中定義了一個getInputStream方法來返回這個字節輸入流對象。爲了方便讀取純文本形式的實體內容,ServletRequest接口也定義了一個getReader方法,以返回一個表明實體內容的字符輸入流對象。
getInputStream與getReader方法
getInputStream返回輸入流對象類型爲ServletInputStream,若是實體內容中包含二進制數據,那麼只能使用getInputStream方法返回的輸入流對象來讀取實體內容。
getReader則返回一個BufferedReader對象。
調用了二者任意一個方法後,就不能再調用另外一方法。
HttpServletRequest對象的最基本和最普遍應用就是獲取瀏覽器傳遞給Web服務器的參數信息,這些參數信息既能夠是HTTP請求消息的請求行中的URL地址後的附加信息,又能夠是Post方式下application/x-www-form-urlencoded編碼格式的實體內容。那麼,如何獲取這兩種參數?
ServletRequest和HttpServletRequest接口中定義了若干方法,這些方法除了能讀取HTTP請求消息的請求行的URL地址後的附件信息外,還能讀取Post方式下的application/x-www-form-urlencoded編碼格式的實體內容。
getParameter方法:若是請求消息中沒有包含指定名稱的參數,該方法返回null,即getParameter("firstname"),不存在這個參數返回null;若是指定名稱的參數存在但沒有設置值,返回一個空串;若是包含多個指定名稱相同的參數,返回第一個出現的參數值。另外,該方法對參數名大小寫敏感。
getParameterValues方法:該方法用於獲取某個指定名稱的全部參數的值,並以一個String數組的形式返回這些參數值。若是參數值只有一個,返回的數組的長度就爲1,其中包含的元素值與getParameter方法返回的值同樣。
getParameterNames方法:返回一個包含請求消息中全部參數名的Enumeration對象。
getParameterMap方法:返回一個將請求消息中全部參數名和值裝進Map的Map對象
問:何爲隱藏表單字段?
答:在form表單中可使用隱藏表單字段元素向服務器傳遞參數信息,瀏覽器在網頁上不會顯示出隱藏表單字段元素,但當提交表單時,瀏覽器會將這個隱藏表單字段元素的name屬性和value屬性做爲參數傳遞給web服務器。
ServletRequest接口的實現類一般都是採用一個HashMap對象來存儲某些對象,setAttribute方法就是向這個HashMap對象中增長與某個名稱綁定的對象,getAttribute方法則是根據名稱從這個HashMap對象中檢索對象。這種存儲在ServletRequest對象中的對象稱之爲請求域屬性。
setAttribute(String name, Object o),若是ServletRequest對象中已經存在指定名稱的屬性,若屬性值對象爲null則至關於removeAttribute,不然即覆蓋原來對象。
getAttribute(String name),返回指定名稱的屬性對象。
removeAttribute(String name),刪除指定名稱的屬性對象。
getAttributeNames(),返回一個包含ServletRequest對象中全部屬性名的Enumeration對象。