Servlet规范之转发请求

Posted 顧棟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);

用于创建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

这些属性可以通过请求对象上的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

这些属性的值必须等于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

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

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

以上是关于Servlet规范之转发请求的主要内容,如果未能解决你的问题,请参考以下文章

servlet范围:数据共享

java中过滤器和拦截器的区别

servlet如何重定向

从零开始的Java开发2-10-4 Servlet与jsp进阶:请求与响应的结构请求转发与响应重定向Cookie

Servlet规范之Servlet顶层接口

servlet之转发与重定向的区别