• Servlet规范之转发请求


    Dispatching Requests

    文章是对 JSR-000340 JavaTM Servlet 3.1 Final Release的Java™ Servlet规范的翻译,尚未校准

    将RequestDispatcher理解为请求分配或调度器,实现请求的转发功能。

    当建立一个Web应用程序时,将一个请求的处理转发给另一个servlet,或者将另一个servlet的输出包含在响应中,往往是有用的。RequestDispatcher接口提供了一种机制来实现这一点。

    当请求的异步处理被启用时,AsyncContext允许用户将请求分派回Servlet容器。

    获取RequestDispatcher

    一个实现RequestDispatcher接口的对象可以通过以下方法从ServletContext获得:

    • getRequestDispatcher
    • getNamedDispatcher

    getRequestDispatcher方法需要一个String参数,描述ServletContext范围内的一个路径。这个路径必须是相对于ServletContext的根部,以"/"开头,或者是空的。该方法使用该路径查找一个Servlet,使用第12章 "Mapping Requests to Servlets"中的Servlet路径匹配规则,用一个RequestDispatcher对象来包装它,并返回结果对象。如果不能根据给定的路径解析servlet,则提供一个RequestDispatcher,返回该路径的内容。

    getNamedDispatcher方法接受一个字符串参数,表示ServletContext已知的Servlet名称。如果找到一个servlet,它将被包裹在一个RequestDispatcher对象中,并返回该对象。如果没有servlet与给定的名称相关联,该方法必须返回null。

    为了允许使用相对于当前请求的路径(而不是相对于ServletContext的根)获得RequestDispatcher对象,在ServletRequest接口中提供了getRequestDispatcher方法。

    这个方法的行为与ServletContext中的同名方法类似。Servlet容器使用请求对象中的信息,将针对当前Servlet的给定相对路径转换为完整路径。例如,在一个根植于’/'的上下文和一个对/garden/tools.html的请求中,通过ServletRequest.getRequestDispatcher("header.html")获得的请求调度器的行为与调用ServletContext.getRequestDispatcher("/garden/header.html")完全一样。

    请求调度器路径中的查询字符串

    使用路径信息创建RequestDispatcher对象的 ServletContex ServletRequest方法,允许在路径上附加查询字符串信息。例如,开发者可以通过使用以下代码获得一个RequestDispatcher

    String path =/raisins.jsp?orderno=5;
    RequestDispatcher rd = context.getRequestDispatcher(path);
    rd.include(request, response);
    
    • 1
    • 2
    • 3

    用于创建RequestDispatcher的查询字符串中指定的参数优先于传递给所包含的Servlet的其他同名参数。与RequestDispatcher相关的参数只在includeforward调用期间适用。

    参数优先级

    请求调度器的使用

    为了使用一个请求调度器,Servlet会调用RequestDispatcher接口的include方法或forward方法。这些方法的参数可以是通过javax.servlet.Servlet接口的服务方法传入的requestresponse参数,也可以是为2.3版规范引入的请求和响应包装器类的子类实例。在后一种情况下,包装器实例必须包装容器传递到 service 方法中的请求或响应对象。

    容器提供者应确保将请求分派给目标Servlet的过程与原始请求发生在同一JVM的同一线程中。

    Include method

    RequestDispatcher接口的include方法可以在任何时候被调用。包含方法的目标Servlet可以访问请求对象的所有方面,但它对响应对象的使用是比较有限的。

    它只能将信息写入响应对象的ServletOutputStream或Writer,并通过写入超过响应缓冲区末端的内容,或明确调用ServletResponse接口的flushBuffer方法来提交响应。除了HttpServletRequest.getSession()HttpServletRequest.getSession(boolean)方法外,它不能设置头信息或调用任何影响响应头信息的方法。

    任何试图设置头信息的行为都必须被忽略,如果响应已经被提交的情况下,任何对HttpServletRequest.getSession()HttpServletRequest.getSession(boolean)的调用来实现添加Cookie响应头时,必须抛出IllegalStateException

    如果默认Servlet是RequestDispatch.include()的目标,并且请求的资源不存在,那么默认Servlet必须抛出FileNotFoundException。如果这个异常没有被捕获和处理,而且响应还没有被提交,那么状态代码必须被设置为500。

    Include方法的参数

    除了通过使用getNamedDispatcher方法获得的Servlet,被另一个Servlet使用RequestDispatcherinclude方法调用的Servlet可以访问它被调用的路径。

    以下请求属性必须被设置:

    javax.servlet.include.request_uri
    javax.servlet.include.context_path
    javax.servlet.include.servlet_path
    javax.servlet.include.path_info
    javax.servlet.include.query_string
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这些属性可以通过请求对象上的getAttribute方法从被包含的servlet中访问,它们的值必须分别等于请求URI、上下文路径、servlet路径、路径信息和被包含servlet的查询字符串。如果该请求随后被包含,这些属性将被替换为该包含。

    如果包含的servlet是通过使用getNamedDispatcher方法获得的,这些属性必须不被设置。

    Forward Method

    RequestDispatcher接口的forward方法只有在没有向客户端提交输出的情况下才可以被调用的servlet调用。如果响应缓冲区中存在尚未提交的输出数据,必须在调用目标servlet的service方法之前清除这些内容。如果响应已经被提交,必须抛出一个 “非法状态异常”(IllegalStateException)。

    暴露给目标Servlet的请求对象的路径元素必须反映用于获取RequestDispatcher的路径。

    唯一的例外是如果RequestDispatcher是通过getNamedDispatcher方法获得的。在这种情况下,请求对象的路径元素必须反映原始请求的元素。

    RequestDispatcher接口的forward方法毫无例外地返回之前,响应内容必须被发送和提交,并由servlet容器关闭,除非该请求被放入异步模式。如果在RequestDispatcher.forward()的目标中发生错误,该异常可能会通过所有调用的过滤器和servlet传播回来,最终回到容器中。

    查询字符串

    请求调度机制负责在转发或包括请求时汇总查询字符串参数。

    Forward方法的参数

    除了通过使用getNamedDispatcher方法获得的Servlet,被另一个Servlet使用RequestDispatcherforward方法调用的Servlet可以访问原始请求的路径。

    以下请求属性必须被设置:

    javax.servlet.forward.request_uri
    javax.servlet.forward.context_path
    javax.servlet.forward.servlet_path
    javax.servlet.forward.path_info
    javax.servlet.forward.query_string
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这些属性的值必须等于HttpServletRequest方法getRequestURIgetContextPathgetServletPathgetPathInfogetQueryString的返回值,分别在传递给从客户端接收请求的调用链中第一个Servlet对象的请求对象上调用。

    这些属性可以通过请求对象上的getAttribute方法从转发的servlet访问。请注意,这些属性必须始终反映原始请求中的信息,即使在调用多个转发和后续包含的情况下也是如此。

    如果被转发的servlet是通过使用getNamedDispatcher方法获得的,这些属性必须不被设置。

    错误的处理

    如果作为请求分派器目标的Servlet抛出了一个运行时异常或一个ServletExceptionIOException类型的检查异常,它应该被传播给调用的Servlet。所有其他的异常都应该被包装成ServletExceptions,并将异常的根本原因设置为原始异常,因为它不应该被传播。

    获取 AsyncContext

    一个实现AsyncContext接口的对象可以通过startAsync方法从ServletRequest中获得。一旦你有了AsyncContext,你可以用它通过complete()方法完成请求的处理,或者使用下面描述的一个调度方法。

    Dispatch Method

    以下方法可用于从AsyncContext调度请求。

    • dispatch(path)

    dispatch方法接受一个字符串参数,描述ServletContext范围内的一个路径。这个路径必须是相对于 ServletContext 的根,并且以"/"开头。

    • dispatch(servletContext, path)

    dispatch方法需要一个字符串参数,描述指定的ServletContext范围内的路径。这个路径必须是相对于指定的 ServletContext 的根,并且以"/"开头。

    • dispatch()

    dispatch方法不需要参数。它使用原始URI作为路径。如果AsyncContext是通过startAsync(ServletRequest, ServletResponse)初始化的,并且传递的请求是HttpServletRequest的实例,那么分派到HttpServletRequest.getRequestURI()返回的URI。否则,派发到请求的URI,当它最后被容器派发时。

    AsyncContext接口的一个调度方法可以被等待异步事件发生的应用程序调用。如果在AsyncContext上调用了complete(),必须抛出IllegalStateException。所有调度方法的变化都会立即返回,并且不提交响应。

    暴露给目标Servlet的请求对象的路径元素必须反映在AsyncContext.dispatch中指定的路径。

    查询字符串

    请求调度机制负责在调度请求时汇总查询字符串参数。

    Dispatch 方法的参数

    通过使用AsyncContextdispatch方法调用的servlet可以访问原始请求的路径。

    以下请求属性必须被设置:

    javax.servlet.async.request_uri
    javax.servlet.async.context_path
    javax.servlet.async.servlet_path
    javax.servlet.async.path_info
    javax.servlet.async.query_string
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这些属性的值必须等于HttpServletRequest方法getRequestURIgetContextPathgetServletPathgetPathInfogetQueryString的返回值,分别在传递给调用链中第一个接收客户端请求的Servlet对象的请求对象上调用。

    这些属性可以通过请求对象上的getAttribute方法从被派遣的servlet访问。请注意,这些属性必须始终反映原始请求中的信息,即使是在调用多个调度的情况下。

  • 相关阅读:
    网络时钟程序Net_Clock
    Nest 的实现原理?理解了 reflect metadata 就懂了
    一文告诉你什么是 Kubernetes
    1467. 两个盒子中球的颜色数相同的概率 数学+DFS
    c++运算符重载
    java图片转二进制流_java将文件转化成二进制流
    没域名也可以frp实现内网穿透 SSH,个人搭建内网穿透 7月6日
    【NGINX入门指北】 基础篇
    使用opencv及FFmpeg编辑视频
    【PostgreSQL内核学习(十五)—— (ExecutorRun)】
  • 原文地址:https://blog.csdn.net/weixin_43820556/article/details/127823237