標籤:style http io ar color os 使用 sp java
1.HttpServlet簡介
HttpServlet根據客戶發出的HTTP請求,產生響應的HTTP響應結果。HttpServlet首先必須讀取HTTP請求的內容。Servlet容器負責建立HttpRequest對象,並把HTTP請求資訊封裝到HttpRequest對象中,這大大簡化了HttpServlet解析請求資料的工作量。如果沒有HttpServletRequest,HttpServlet只能直接處理Web客戶發出的原始的字串資料。
2.HttpServlet源碼分析
HttpServlet繼承GenericServlet。GenericServlet為抽象類別,HttpServlet也是一個抽象類別,但是HttpServlet中定義了關於HTTP協議的支援方法。其中定義了支援的要求方法,與請求處理的具體邏輯。
支援的請求方法有:
private static final String METHOD_DELETE = "DELETE"; private static final String METHOD_HEAD = "HEAD"; private static final String METHOD_GET = "GET"; private static final String METHOD_OPTIONS = "OPTIONS"; private static final String METHOD_POST = "POST"; private static final String METHOD_PUT = "PUT"; private static final String METHOD_TRACE = "TRACE";
protected void doGet(HttpServletRequest req, HttpServletResponse resp)protected void doHead(HttpServletRequest req, HttpServletResponse resp)protected void doPost(HttpServletRequest req, HttpServletResponse resp)protected void doPut(HttpServletRequest req, HttpServletResponse resp)protected void doDelete(HttpServletRequest req,HttpServletResponse resp)protected void doOptions(HttpServletRequest req,HttpServletResponse resp)protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
具體處理邏輯(GET為例):
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); } }
先擷取請求的http協議,如果是http1.1則返回405,否則返回400.這裡只是簡單的處理,所有自訂的servlet一般都繼承HttpServlet,重寫請求方法的處理邏輯。doGet的參數有HttpServletRequest和HttpServletResponse。HttpServletRequest包含了HTTP的請求資訊,HttpServletResponse則包含的是響應資訊。(HttpServletRequest,HttpServletResponse都是由web容器建立的。)
處理處理請求的各個協議外,還有一個請求接收的總方法service
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request; HttpServletResponse response; if (!(req instanceof HttpServletRequest && res instanceof HttpServletResponse)) { throw new ServletException("non-HTTP request or response"); } request = (HttpServletRequest) req; response = (HttpServletResponse) res; service(request, response); }
調用
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); if (method.equals(METHOD_GET)) { long lastModified = getLastModified(req); if (lastModified == -1) { // servlet doesn‘t support if-modified-since, no reason // to go through further expensive logic doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < lastModified) { // If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified); doGet(req, resp); } else { resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } } } else if (method.equals(METHOD_HEAD)) { long lastModified = getLastModified(req); maybeSetLastModified(resp, lastModified); doHead(req, resp); } else if (method.equals(METHOD_POST)) { doPost(req, resp); } else if (method.equals(METHOD_PUT)) { doPut(req, resp); } else if (method.equals(METHOD_DELETE)) { doDelete(req, resp); } else if (method.equals(METHOD_OPTIONS)) { doOptions(req,resp); } else if (method.equals(METHOD_TRACE)) { doTrace(req,resp); } else { // // Note that this means NO servlet supports whatever // method was requested, anywhere on this server. // String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[1]; errArgs[0] = method; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); } }
可見請求是以service按照請求的方法分發到各個要求方法處理邏輯中去的。
long lastModified = getLastModified(req);
這裡調用了本類的protected方法:getLastModified
protected long getLastModified(HttpServletRequest req) { return -1; }
此方法返回都是-1。此方法和緩衝有關。具體邏輯如下:
在http協議中,瀏覽器對訪問過的頁面緩衝後,它將會在以後訪問該頁面時,將會根據LastModified頭欄位指定的時間值產生If-Modified-Since頭欄位,作為快取頁面面的最新更新時間。如果網頁的最後修改時間比If-Modified-Since頭欄位指定的時間早的話,web伺服器就會請求的頁面,如果自If-modified-Since指定的時間以來,網頁內容沒有被修改的話,伺服器就會返回一個304回應標頭,一次告訴瀏覽器繼續使用已緩衝的頁面。 繼承HttpServlet的servlet程式在接收到用戶端的GET請求後,HttpServlet的重載service方法會先調用getLastModified方法,根據這個方法的傳回值來決定是否要調用doGet方法和產生Last-Modified頭欄位。主要有以下三種決定方式:
1.如果getLastModified方法的傳回值是一個負數的話,不管用戶端的請求資訊如何,service方法都會調用doGet方法產生響應資訊返回給用戶端。
2.如果getLastModified方法的傳回值是一個正數,並且用戶端的請求訊息中沒有包含If-Modified-Since頭欄位的(這種情況是第一次訪問該頁面時)或者是請求訊息中包含If-Modified-Since頭欄位,但是傳回值比If-Modified-Since頭欄位指定的時間新的話,則service方法調用doGet方法產生響應資訊和Last-Modified訊息頭返回給用戶端。
3.如果getLastModified方法的傳回值是一個正數,並且傳回值比用戶端發出的請求訊息中If-Modified-Since頭欄位指定的時間值舊的話,那麼service方法將不會調用doGet方法和產生Last-Modified頭字段,而是返回一個304狀態給用戶端,表示讓用戶端繼續使用以前緩衝的頁面。
另外HttpServlet中還包含兩個類:NoBodyResponse、NoBodyOutputStream。此次兩個類不做討論。
HttpServlet的源碼分析到此。
HttpServlet源碼分析