Java Web中的request,response,重定位與轉發的詳解

ihav2carryon發表於2024-08-18

request與response響應

Web伺服器接收到客戶端的http請求,其會對每一次的http請求分別建立應該代表請求的request物件,和一個代表響應的response物件. request是獲取客戶端提交的資料,response是向客戶端提供資料.

request

  • 一個request請求由以下資料組成
    • 請求方法:表示客戶端將要執行的操作,例如 GET,POST,PUT,DELETE等等
    • 請求URL:客戶端想要訪問資源地址
    • 請求頭:包含有關請求的後設資料,如Content-Type ,User-Agent ,Accept-Languge
    • 請求體:其包括髮送給伺服器的資料,例如資料表單,JSON資料等等
    • 請求引數:包含在URL中的引數,傳遞伺服器所需的資料

response

  • 一個response響應包括以下幾個資料
    • 狀態碼:一個三位數字的狀態碼,請求的結果,如200 OK ,404Not Found ,500 Internal Server Error
    • 響應頭:response的響應頭與request的請求頭的資料型別是一致的,Content-Type ,User-Agent ,Accept-Languge
    • 響應體:包含伺服器返回給客戶端的資料,例如HTML頁面.JSON資料,圖片等

HttpServletRequest與HttpServletResponse

HttpServletRequestHttpServletResponse 分別是ServletRequesServletResponse的子介面,Http介面是專門處理HTTP協議的介面

ServletRequesServletResponse 是Servlet API中的頂級介面,與HttpServletRequestHttpServletResponse 不同的是,前者是處理請求/響應的基本介面,其定義了多種請求/響應的介面可適用多種協議,不僅是HTTP請求

HttpServletRequest

以下主要介紹對於HttpServletRequest四個應用方面,其中也借鑑了同平臺創造者@Evan Liu

獲取客戶端的資訊的常用方法

  • String getRequestURL() :返回客戶端發出請求的完整URL
  • String getRequestURI() :返回請求行中部分資源名
  • String getQueryString() :返回請求行中的引數部分
  • String getRemoteAddr() :返回發出請求的客戶端的IP地址
  • String getMethod() 獲得客戶機請求方式
  • getContextPath():獲取工程虛擬目錄的名稱

Eg:

@WebServlet("/test")
public class MyHttpServlet01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(req.getRequestURL());
        System.out.println(req.getRequestURI());
        
        System.out.println(req.getQueryString());
       
        System.out.println(req.getRemoteAddr());
        System.out.println(req.getMethod());
        System.out.println(req.getContextPath());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("執行POST請求業務邏輯");
    }

獲取請求頭資訊

  • String getHeaders(String var1):獲取頭資訊的值,將其轉化為一個字串,var1 :請求頭的名稱,例如:
    "Accept-Encoding","User-Agent""Content-Type" 等等

  • Enumeration<String> getHeaders(String var1) :獲取頭資訊的值,返回應該Enumeration<String>型別的陣列

  • Enumeration<String> getHeaderNames(String var1) :獲取所有頭資訊名稱,返回應該Enumeration<String>型別的陣列

    • Enumeration:列舉介面,是一種特殊的資料型別,主要用於遍歷集合元素,是個較老的技術,現在主流使用IteratorIterable

    eg:

    @WebServlet("/test")
    public class MyHttpServlet01 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            System.out.println("getHeaders:"+req.getHeaders("Accept-Encoding"));
            //獲取http請求頭中的referer防盜鏈
            System.out.println("getHeaders:"+req.getHeader("referer"));
    
            System.out.println("--------------------------------------------------");
            Enumeration<String> headerNames = req.getHeaderNames();
            while(headerNames.hasMoreElements())
            {
                String name=headerNames.nextElement();
                System.out.println(name+":"+req.getHeader(name));
            }
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("執行POST請求業務邏輯");
        }
    }
    
    

獲取請求引數資訊

  • String getParameter(String name):獲取一個指定名稱的請求引數的值,沒找到則返回null
  • String getParameterValues(String name):獲取指定名稱的請求引數的所有值,即一個引數有多值,則返回所有,沒找到則返回null
  • Enumeration<String> getParameterNames() :獲取請求中的所有引數名
  • Map<String, String[]> getParameterMap() :獲取請求中的所有引數及其對映

eg:

@WebServlet("/test")
public class MyHttpServlet01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String parameter = req.getParameter("value");
        String[] values = req.getParameterValues("value");
        Enumeration<String> parameterNames = req.getParameterNames();
        Map<String, String[]> parameterMap = req.getParameterMap();

        System.out.println(parameter);
        System.out.println(Arrays.toString(values));

        while(parameterNames.hasMoreElements())
        {
            String str=parameterNames.nextElement();
            System.out.println(str);
        }

        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String str = entry.getKey();
            String[] string = entry.getValue();
            System.out.print(str+":");
            System.out.println(Arrays.toString(string));
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("執行POST請求業務邏輯");
    }
}

請求轉發

在Java Web 請求轉發是一個十分常用的技術,其用於在一個Web應用內部,從一個資源如(Servlet),跳轉到另一個資源,實現資源的分佈利用

請求轉發的原理

  • 當一個Servlet接收到客戶端的請求後,其可以決定將請求轉發給另一個資源來處理.這種情況下,原始請求的上下文如(請求引數,請求頭等等) 都會傳遞到目標資源,客戶端是無法察覺到發生了轉發

轉發方式

Java中,提供了一個RequestDispatcher 介面,用於實現請求轉發和請求包含,這在處理複雜的Web應用邏輯時非常有用

  • RequestDispatcher的主要方法

    • void forward(ServletRequest var1,ServletResponse var2 :將當前請求轉發到指定的目標資源,傳遞原始請求和響應物件
    • void include(ServletRequest var1, ServletResponse var2) :將指定的目標資源包含到當前響應中,目標資源的輸出會被合併到當前響應中
  • ServletRequest請求範圍方法

    Java Web開發中ServletRequest介面提供的方法可以讓一些屬性在一個請求的生命週期被多個資源共享

    • void setAttribute(String name, Object object) :其用於將一個 <名稱-物件> 對新增到請求範圍,在之後的業務邏輯中使用
      • 底層原理:
        • 儲存原理:當呼叫了setAttribute方法時,ServletRequest介面會建立一個內部對映Map,將其<名稱-物件>對新增在其中,該Map是一個執行緒安全的資料結構,適於儲存範圍屬性
        • 作用範圍:作用範圍通常是一次HTTP請求的生命週期內,則說明儲存在Map中的屬性只能在處理當前的過程中可用,請求處理結束後,這些屬性就自動銷燬
        • 共享屬性:透過setAttribute 儲存的屬性可以在處理不同階段被多個資源訪問,則意味著可以在不同的Servlet之間共享資料
    • Object getAttribute(String name) :用於獲取指定名稱的請求屬性的值,沒有檢索到則訪問null
    • viod removeAttribute(String name) :用於從請求範圍中刪除指定名稱的屬性

轉發的特性

  • 伺服器端操作:轉發操作是伺服器的操作,客戶端不會察覺到, 瀏覽器的位址列URL不會發生變化
  • 相對路徑:轉發時通常使用相對路徑來指定目標資源位置,目標資源必須位於同一個Web應用中
  • 生命週期:請求轉發發生在同一個請求生命週期中,異常轉發後可以共享一個HttpServletRequestHttpServletResponse

HttpServletResponse

HttpServletResponse 封裝伺服器向客戶端傳送響應資料資訊

常用的response方法

  • void setStatus(int status) :用於設定HTTP響應狀態碼,通常用於指示客戶端是否成功以及如何處理響應,status:HTTP響應狀態碼,如200 OK404 Not Found

  • void setHeader(String name, String value) :設定一個帶有給定名稱和值的Header,若name已存在,則直接覆蓋

  • ServletOutputStream getOutputStream() :獲取一個ServletOutputStream 位元組流物件,輸出響應體內容

  • PrintWriter getWriter() :獲取一個PrintWriter字元流物件,輸出響應體內容,PrintWriter實際上繼承了Writer

  • 狀態響應碼

    狀態響應碼用於表示伺服器對客戶端請求的響應狀態,狀態碼都是有一個三位數字程式碼和一個簡短的描述組成,狀態碼可分為五種:1xx,2xx,3xx4xx,5xx

    • 1XX(資訊狀態碼)

      此類狀態碼錶示請求已經被伺服器接收,但仍需進一步處理

      • 100 Continue:通常用於POST請求,表示伺服器告知客戶端已經接收了一部分,客戶端可以繼續傳送剩餘部分
      • 101 Switching Protocols:切換伺服器協議,通常用於將HTTP協議升級到WebSocket協議
    • 2XX(成功協議)

      此類狀態碼錶示請求已經被成功處理

      • 200 OK:表示請求已經成功處理,響應中包含了請求的資料
      • 201 Created:表示已經建立了一個資源,通常用於POST請求,當建立了一個資源返回
      • 202 Accepted:表示伺服器已經接受了請求,但仍未處理,通常用於非同步處理
      • 204 Not Content:表示伺服器成功處理了請求,但沒有返回內容
    • 3XX(重定向狀態碼)

      此類狀態碼錶示客戶端還要採用進一步操作來無參指示

      • 301 Moved Permanently:表示伺服器資源被永久性地轉移到一個新的URL,客戶端(瀏覽器)將自動地將資源重定向到新URL

      • 302 Found (Previously "Moved Temporarily"):其表示請求的資源被暫時轉移到一個新URL,同樣客戶端會自動將其資源重定向到新URL

      • 4XX(客戶端錯誤狀態碼)

        此類狀態碼錶示客戶端的請求存在錯誤

        • 400 Bad Request:其表示客戶端傳送的請求語法錯誤或無法被伺服器正確解析理解
        • 401 Unauthorized:其表示客戶端嘗試訪問需要身份驗證的資源,但未提供有效的認證資訊
        • 403 Forbidden:表示有足夠的許可權訪問資源,但被伺服器拒絕,
        • 404 Not Found:伺服器找不到請求的資源
        • 405 Method Not Allowed:表示請求的方法不允許用於請求資源
      • 5XX(伺服器錯誤狀態碼)

        • 500 Internal Server Error:通常表示伺服器遇到了不可預計的情況,無法完成請求,通常表示伺服器內部錯誤
        • 501 Not Implemented:表示伺服器不支援請求的方法,例如伺服器可能不支援PUT方法
        • 502 Bad Gateway:表示閘道器或代理工作的伺服器接收到了無效的響應
        • 503 Service Unavailable:表示伺服器當前無法使用(超載或停機)
        • 504 Gatew TimeOut:表示作為閘道器或代理工作的伺服器沒有及時從上游伺服器收到請求

重定位

重定位(Redirect)是一個常見的技術,用於將一個客戶端請求從一個資源重定位到另一個資源,重定位與轉發不同,重定位會建立一個新的HTTP請求

  • 重定位的方式

    在Servlet API中,HttpServletResponse介面提供了一個方法實現重定位

    • void sendRedirect(String location) :將客戶端重定位到相應的URL,location:目標URL地址

    eg:

    
    @WebServlet("/test01")
    public class MyHttpServlet01 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           //設定輸出文字格式,即編碼格式
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter writer = resp.getWriter();
            writer.println("<p>這是第一個servlet</p>");
           //進行轉發到/test02
            resp.sendRedirect("/test02");
        }
    }
    //
    @WebServlet("/test02")
    public class MyHttpServlet02 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter writer = resp.getWriter();
            writer.println("<p>這是第二個servlet</p>");
        }
    }
    

    當向瀏覽器訪問/test01時,瀏覽器會接受到第一個Servlet的響應,接著會重定位到/test02.再次發起請求,客戶端會看到兩次跳轉和以下介面

  • 重定位的原理

    • 伺服器接收到請求後,會提供其HTTP響應碼判斷是否要進行重定位操作,若狀態碼為302 Found(或301 Moved Permanently)會檢視其響應頭(Response Headers)中的Location屬性,並根據其進行重定位
    • 客戶端接收到重定位響應,解析出新的跳轉位置時,會再次發起一次HTTP請求到新位置
    • sendRedirect() 實際是設定了請求頭中的Status Code(狀態響應碼)和響應頭中的Location屬性

重定位與轉發的區別

轉發和重定向都是實現頁面的跳轉,他們都是訪問一個Servlet時,Servlet會幫我們跳轉到另一個介面,只是實現方法不同,以下內容借鑑了創造者 @萌小Q

  • 從URL位址列來說
    • forward是伺服器請求資源,伺服器之間訪問目標地址的URL,伺服器將目標URL響應內容傳送給客戶端(瀏覽器),實際上瀏覽器不知道伺服器傳送的內容是從哪裡來的,其操作是伺服器實現的
    • redirect是伺服器根據業務邏輯傳送一個狀態碼,告知瀏覽器重新去請求新的URL,因此重定位位址列的URL會相應改變
  • 資料共享
    • forward:被轉發的頁面和轉發後的頁面都可以共享request 作用域裡的資料
    • redirect:不能共享資料
  • 用途方面
    • forward:一般用於使用者登入時,根據角色轉發相應模板
    • redirect:一般用於使用者登出登入時放回主頁面或是跳轉到其他網站等等
  • 效能方面
    • forward:較高效率
    • redirect:效率較低

底層本質區別

forward(轉發)是伺服器行為,redirect(重定向)是客戶端行為

  • 行為動作
    • forward行為:客戶端(Browser)發起http請求→web伺服器(例如 Tomcat)接收請求→呼叫其內部一個方法完成請求處理或轉發動作→將請求響應的資源返回給客戶端;對於forward,轉發的路徑必須是同一個web容器下的URL,不能轉向到另一個web路徑上,轉遞的是request ,轉發認為瀏覽器只做了一次訪問請求
    • redirect 行為:客戶端傳送http請求→web伺服器接收後傳送302狀態響應碼和對於的location給客戶端→客戶端檢查響應頭發現是302響應,則在次傳送一次http請求,請求的是location中新的URL→伺服器根據請求響應相應的資源返回客戶端,由於是瀏覽器重新發起請求,那跟中間的request傳遞沒有關係,重定位是客戶端至少做了兩次訪問操作
  • 操作許可權
    • forward:是將伺服器內部將一個requestresponse的處理許可權,交付給另一個Servlet
    • redirect :是客戶端request A,伺服器響應,並response回來,告訴瀏覽器你應該去B,重定向可以訪問自己web應用以外的資源
  • 注意事項
    • redirect(重定向):跳轉後必須加上return要不然頁面雖然跳轉了但是還會執行跳轉後面的語句
    • forward(轉發):是執行了跳轉頁面下面的程式碼就不會在執行了

相關文章