Java Web中的request,response,重定位与转发的详解

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:

java 复制代码
@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:

    java 复制代码
    @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:

java 复制代码
@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:

    java 复制代码
    @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(转发):是执行了跳转页面下面的代码就不会在执行了