HTTP的請求與響應
當發生下列事件時,瀏覽器都會向Web伺服器發送HTTP請求:
1.使用者在網頁上點擊一個超連結;
2.使用者提交在網頁上填好的表單;
3.使用者在瀏覽器地址欄中輸入URL地址並斷行符號。
Servlet中對HTTP請求的處理過程:
1.Web瀏覽器通過開啟一個到Web伺服器的TCP Socket通訊端初始化一個HTTP請求,Socket的輸入資料流包含了HTTP請求資料,Socket的輸出資料流中包含了HTTP響應數。
2.對於一個Servlet的每次訪問請求,Web容器都會解析Socket輸入資料流中的HTTP請求資料,建立一個請求對象,同時也建立一個響應對象。
3.Web容器調用所請求的Servlet對象的service()方法,並將請求和響應對象作為參數傳遞給該方法,其中作為參數傳遞進來的響應對象就是HttpServletResponse對象,在Servlet對象的service()方法內部可以調用HttpServletRespnse對象的各種方法來建立響應訊息。
4.HttpServletResponse響應對象給Servlet提供一個PrintWriter對象,使Servlet可以產生響應訊息體。
使用者在提交網頁或表單時,瀏覽器向伺服器發送的要求方法有以下幾種:GET,HEAD,POST,PUT,DELETE,OPTION,REACE,在Servlet中每一種方法都對象一個要求方法,在使用時,我們一般只需在Servlet中實現需要的方法即可。要求方法最常用的是GET和POST方法,在以下這些條件下使用這兩種方法:1.請求一個靜態頁面或圖形檔案時使用GET方法,因為僅需要傳送檔案名;2.發送大資料時,使用POST方法;3.上傳檔案時,使用POST方法;4.發送使用者名稱、密碼或其它保密資訊時使用POST方法。
在Servlet中我們需要訪問請求行的資訊,需要用請求對象調用以下的方法:
getMethod():擷取HTTP的要求方法,如:GET和POST等
getRequestURI():擷取請求的URI資源,如:/lovobook/index.html
getRequestURL():擷取請求的URL,包含協議名、伺服器名或IP、連接埠號碼和請求資源但不包括查詢字串參數,如:http://127.0.0.1:8080/lovobook/index.html
getQueryString():擷取請求URL後面的查詢字串,如:name=aaa(POST沒有這個方法)
getProtocol():擷取協議名和版本號碼,如:HTTP/1.1
getContextPath():擷取請求URI資源的上下文路徑,始終以"/"開頭,如:/lovobook
getServletPath():擷取Servlet的映射路徑(參見http://hi.baidu.com/pangang107/blog/item/fd664d2d0cad45f48b139925.html中Servlet在web.xml中的部署)
HTTP要求標頭通過HttpServletRequest對象的下列方法調用:
getHeader(String name):返回要求標頭的值,如沒有則返回null
getHeaders(String name):如果請求的值有多個,用此方法返回一個Enumeration枚舉包含這些值
getHeaderNames():返回一個Enumeration包含所有的要求標頭的名稱
getIntHeader(String name):擷取要求標頭的值,並轉換為int類型,不存在則返回1,不能轉換則跑異常,NumberFormatException
getDateHeader(String name):擷取特定要求標頭的值,並轉換為Date類型
通過請求對象HttpServletRequest調用以下方法獲得請求參數,即表單資料:
getParameter(String parameterName):通過參數名(區分大小寫,與表單參數名相同)獲得表單參數值,對GET/POST方法都適用,如果沒有這個參數,則返回null
getParameterValues(String parameterName):返回一個數組包含,這個參數名的所有值
getParameterNames():返回一個Enumeration包含所有的參數名
注意,如果上傳檔案時網頁上表單應包含這些參數:
<form type="file" method="post" enctype="mutipart/form-data">
....
</form>
請求轉寄可以通過javax.servlet.RequestDispatcher對象來實現,RequestDispatcher對象可以通過下列方式得到:
getRequestDispatcher(String path):path路徑必須以根目錄"/"開始,並且可以導向Web應用程式中的任何資源,如:request.getRequestDispatcher("/HelloWorld"),容器會把這看作是從Web應用程式的根開始,如果不用"/"開始,容器會認為路徑相對於原來的請求。
getNamedDispatcher(String name):name名稱必須在web.xml中servlet-name元素中定義的名稱
通過內容物件ServletContext的getRequestDispatcher()得到,路徑必須以根目錄"/"開始
RequestDispatcher對象提供了兩種方法來包含不同的資源,以及將請求轉寄到不同資源
forward(ServletRequest, ServerletResponse):派發請求和響應對象到RequestDispatcher對象所確定的新資源(Servlet,JSP,或HTML等),該資源通過利用請求和響應對象來處理HTTP請求,用法如:request.getRequestDispatcher("/success.html").forward(request,response);
include(ServletRequest, ServletResponse):用法同forward()方法,有一些限制,它能包含伺服器端的資源,被包含的資源不能改變響應狀態碼或設定頭資訊,任何制式改變的嘗試都會被忽略,一般情況下不用。
響應狀態代碼的設定一般使用response.setStaauts(int)方法,但HttpServletResponse定義了兩種情況的專用方法:
sendError(int code,String message):產生一個404應答,同時產生一個簡短的html錯誤資訊文檔發送給用戶端
sendRedirect(String URL):產生一個302應答,同時在Location中指示新文檔的URL地址,也就是重新導向
設定回應標頭資訊的方法:
containsHeader(String name):返回一個布爾值指示是否設定了指定的回應標頭
setHeader(String name,String value):用一個給定的名稱和字串值設定回應標頭的通用方式,如過回應標頭已本設定,則會覆蓋
setIntHeader(String name,int value):同上,值為int類型
setDateHeader(String name,long date):同上,date為日期值,日期值應該反應自1970-1-1日(GMT)以來的精確到毫秒的長整數
addHeader(String name,String value):用於在response中添加一個給定名稱和字串的回應標頭,而不管是否已經存在同名的前序,因為該方法允許回應標頭有多個值
addIntHeader(String name,int value):同上,值為int類型
addDateHeader(String name,long date):同上,值為日期值的長整型數值
setContentType(String mimetype):設定返回給用戶端的MIME類型,大多數的Servlet都要用這個方法,用法如:responde.setContentType("text/html;charset=utf-8");
addCookie(Cookie c):用於向Set-Cookie前序插入一Cookie,因為可以設定多個Cookie,所有沒有setCookie方法。
重新導向的流程為:1.Web瀏覽器通過HTTP發送請求;2.伺服器端響應的Servlet把真實串連URL地址和302響應碼發送到用戶端;3.響應結束,瀏覽器斷開但前串連,然後在根據Location回應標頭的URL地址,重新發出HTTP請求。設定重新導向:
一般情況下使用絕對位址,並且是完整的URL路徑來實現重新導向,如:
response.sendRedirect("http://127.0.0.1:8080/lovobook/bar.html");
或者從Web應用程式的跟"/"開始,使用一個URL路徑,如:
response.sendRedirect("/lovobook/bar.html");
Web應用程式可以部署到War檔案中執行,HttpServletRequest的getContextPath()方法得到Web應用程式根目錄的絕對路徑,可以用於一個據對URL地址的聯合,如:
response.sendRedirect(request.getContextPath() + "/lovobook/bar.html");
設定自動重新整理和等待頁(不能保證所有的瀏覽器都支援),代碼:
response.setHeader("Refresh","time;URL=url");
如:response.setHeader("Refresh","10;URL=http://127.0.0.1/foo.html");
得到請求中參數的原始位元組資料,可以使用HttpServletRequest對象的getInputStream()方法得到位元組流,或通過getReader()方法來得到字元流,通過這些來訪問表單資料。
得到請求之後伺服器用字元流java.io.PrintWriter對象(通過response.getWriter()來得到)用來返迴文本內容,位元組流ServletOutputStream對象(通過response.getOutputStream()來得到)允許開發人員用來操作位元組流
1、 HttpServletRequest簡介:
(1)WEB用戶端發送給WEB伺服器的HTTP請求訊息分為三個部分:
a) 請求行 POST /demo/login HTTP/1.1
b) 請求訊息頭
c) 訊息本文(也叫實體內容) username=xxxx&password=1234
(2)Servlet API中定義的ServletRequest介面類用於封裝請求訊息。
(3)HttpServletRequest是專用於HTTP協議的ServletRequest子介面,它用於封裝HTTP請求訊息。
(4)在service()方法內部調用HttpServletRequest對象的各種方法來擷取請求訊息。
2、擷取請求行的相關資訊 :
(1)HTTP請求訊息的請求行包括請求方式、資源路徑和HTTP協議版本:
GET /it315/servlet/RequestURI?param1=a¶m2=b HTTP/1.1
(2)getMethod方法返回HTTP請求訊息中的請求方式。
(3)getRequestURI方法返回請求行中的資源名部分。
(4)getQueryString 方法返回請求行中的參數部分。
(5)getProtocol方法返回請求行中的協議名和版本。
(6)getContextPath方法返回請求資源所屬於的WEB應用程式的路徑。
(7)getPathInfo方法返回請求URL中的額外路徑資訊。額外路徑資訊是請求URL中的位於Servlet的路徑之後和查詢參數之前的內容,它以“/”開頭。
(8)getPathTranslated方法返回URL中的額外路徑資訊所對應的資源的真實路徑。
(9)getServletPath方法返回Servlet的名稱或Servlet所映射的路徑。
3、擷取請求行的相關資訊---------舉例
4、擷取網路連接資訊
(1)getRemoteAddr方法返回傳出請求的客戶機的IP地址,其格式為“192.168.0.3”這種形式的字元文本。 (*)
(2)getRemoteHost方法返回傳出請求的客戶機的完整主機名稱,即“pc1.it315.org”這種格式。
(3)getRemotePort方法返回傳出請求的客戶機所使用的網路介面的連接埠號碼。
(4)getLocalAddr方法返回WEB伺服器上接收當前請求的網路介面的IP地址。
(5)getLocalName方法返回WEB伺服器上接收當前請求的網路介面的IP地址所對應的主機名稱。
(6)getLocalPort方法返回WEB伺服器上接收當前請求的網路介面的連接埠號碼。
(7)getServerName方法返回當前請求所指向的主機名稱。
(8)getServerPort方法返回當前請求所已連線的服務器連接埠號碼。
(9)getScheme方法返回請求的協議名,例如http、https或ftp。
(10)getRequestURL方法返回用戶端發出請求時的完整URL。
5、擷取所有要求標頭的編程執行個體
Enumeration headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements())
{
String headerName = (String)headerNames.nextElement();
out.print(headerName + " : " + request.getHeader(headerName) + "<br>");
/*如果要考慮同一個要求標頭名可能出現多次,
那麼應該用下面的程式碼片段代替上面一行程式碼*/
/*Enumeration values = request.getHeaders(headerName);
while(values.hasMoreElements())
{
out.print(headerName + " : " + (String)values.nextElement() + "<br>");
}*/
}
6、利用Referer要求標頭阻止“盜鏈”
String referrer = request.getHeader("referer");
String sitePart = "http://" + request.getServerName();
if(referrer!=null && referrer.startsWith(sitePart))
{
//處理正當的下載請求,這裡只進行示意
out.println("dealing download ...");
}
else
{
//非法下載請求跳轉到本站的下載說明頁
RequestDispatcher rd = request.getRequestDispatcher("/down.html");
rd.forward(request,response);
}