Servlet3.1规范翻译——转发请求

转发请求

构建Web应用时,把请求转发给另一个servlet处理、或在response中包含另一个servlet的输出通常是很有用的。RequestDispatcher接口提供了一种机制来实现这种功能。

当请求启用异步处理时,AsyncContext允许用户将这个请求转发到servlet容器。

9.1 获得一个RequestDispatcher

实现了RequestDispatcher接口的对象,可以从ServletContext中的下面方法得到:

getRequestDispatcher

getNamedDispatcher

getRequestDispatcher方法需要一个String类型的参数描述在ServletContext作用域内的路径。这个路径必须是相对于ServletContext的根路径,或以’/’开头,或者为空。该方法根据这个路径使用servlet路径匹配规则(见第12章,请求映射到servlet)来查找servlet,把它包装成RequestDispatcher对象并返回。如果基于给定的路径没有找到相应的servlet,那么返回这个路径内容提供的RequestDispatcher。

getNamedDispatcher方法使用一个ServletContext知道的servlet名称作为参数。如果找到一个servlet,则把它包装成RequestDispatcher对象,并返回该对象。如果没有与给定名字相关的servlet,该方法必须返回null。

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

此方法的行为与ServletContext中同名的方法相似。Servlet容器根据request对象中的信息把给定的相对路径转换成当前servlet的完整路径。例如,在以’/’作为上下文根路径和请求路径/garden/tools.html中,通过ServletRequest.getRequestDispatcher("header.html")获得的请求调度器和通过调用ServletContext.getRequestDispatcher("/garden/header.html")获得的完全一样。

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

ServletContext和ServletRequest中创建RequestDispatcher对象的方法使用的路径信息中允许附加可选的查询字符串信息。比如,开发人员可以通过下面的代码来获得一个RequestDispatcher:

String path = “/raisins.jsp?orderno=5”;

RequestDispatcher rd = context.getRequestDispatcher(path);

rd.include(request, response);

查询字符串中指定的用来创建RequestDispatcher的参数优先于传递给它包含的servlet中的其他同名参数。与RequestDispatcher相关的参数作用域仅适用于包含(include)或转发(forward)调用期间。

9.2 请求调度器的使用

要使用请求调度器,servlet可调用RequestDispatcher接口的include或forward方法。这些方法的参数既可以是javax.servlet.Servlet接口的service方法传来的request和response对象实例,也可以是本规范的2.3版本中介绍的request和response包装器类的子类对象实例。对于后者,包装器实例必须包装容器传递到service方法中的request和response对象。

容器提供者应该保证分发到目标servlet的请求作为原始请求发生在的同一个JVM的同一个线程中。

9.3 Include方法

RequestDispatcher接口的include方法可能随时被调用。Include方法的目标servlet能够访问request对象的各个方法(all aspects),但是使用response对象的方法会受到更多限制。

它只能把信息写到response对象的ServletOutputStream或Writer中,或提交在最后写保留在response缓冲区中的内容,或通过显式地调用ServletResponse接口的flushBuffer方法。它不能设置响应头部信息或调用任何影响响应头部信息的方法,HttpServletRequest.getSession()和HttpServletRequest.getSession(boolean)方法除外。任何试图设置头部信息必须被忽略,任何调用HttpServletRequest.getSession()和HttpServletRequest.getSession(boolean)方法将需要添加一个Cookie响应头部信息,如果响应已经提交,必须抛出一个IllegalStateException异常。

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

9.3.1 内置请求参数

除了可以用getNamedDispatcher方法获得servlet外,已经被另一个servlet使用RequestDispatcher的include方法调用过的servlet,有权访问被调用过的servlet的路径。

以下的request属性必须被设置:

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

这些属性可以通过包含的servlet的request对象的getAttribute方法访问,它们的值必须分别与被包含servlet的请求RUI、上下文路径、servlet路径、路径信息、查询字符串相等。如果随后的请求包含这些属性,那么这些属性会被后面包含的属性值替换。

如果包含的servlet通过getNamedDispatcher方法获得,那么这些属性不能被设置。

9.4 Forward方法

RequestDispatcher接口的forward方法,只有在没有输出提交到向客户端时,通过正在被调用的servlet调用。如果response缓冲区中存在尚未提交的输出数据,这些数据内容必须在目标servlet的service方法调用前清除。如果response已经提交,必须抛出一个IllegalStateException异常。

request对象暴露给目标servlet的路径元素(path elements)必须反映获得RequestDispatcher使用的路径。

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

在RequestDispatcher接口的forward方法无异常返回之前,响应的内容必须被发送和提交,且由Servlet容器关闭,除非请求处于异步模式。如果RequestDispatcher.forward()的目标发生错误,异常信息会传回所有调用它经过的过滤器和servlet,且最终传回给容器。

9.4.1 查询字符串

在转发或包含请求时请求调度机制负责聚集(aggregating)查询字符串参数。

9.4.2 转发的请求参数

除了可以用getNamedDispatcher方法获得servlet外,已经被另一个servlet使用RequestDispatcher的forward方法调用过的servlet,有权访问被调用过的servlet的路径。

以下的request属性必须设置:

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的getRequestURI,、getContextPath、 getServletPath、getPathInfo、getQueryString方法的返回值相等,这些方法在从客户端接收到的request对象上调用,值传递给调用链中的第一个servlet对象。

(在request对象上调用从客户端接收请求的调用链中的第一个servlet对象)

这些属性通过转发servlet的request对象的getAttribut方法访问。请注意,即使在多个转发和相继的包含(subsequent includes)被调用的情况下,这些属性必须始终反映原始请求中的信息。

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

9.5 错误处理

如果请求分发的目标servlet抛出运行时异常或受检查类型异常ServletException 或 IOException,异常应该传播到调用的servlet。所有其它的异常都应该被包装成ServletExceptions,异常的根本原因设置成原来的异常,因为它不应该被传播。

9.6 获得一个异步上下文对象

实现了AsyncContext接口的对象可从ServletRequest的一个startAsync方法中获得,一旦有了AsyncContext对象,你就能够使用它的complete()方法来完成请求处理,或使用下面描述的转发方法。

9.7 Dispatch方法

可以使用AsyncContext中下面的方法来转发请求:

dispatch(path)

这个dispatch方法的String参数描述了一个在ServletContext作用域中的路径。这个路径必须是相对于ServletContext的根路径并以’/’开头。

dispatch(servletContext, path)

这个dispatch方法的String参数描述了一个在ServletContext指定作用域中的路径。这个路径必须是相对于ServletContext的根路径并以’/’开头。

dispatch()

这个方法没有参数,它使用原来的URI路径。如果AsyncContext已经通过startAsync(ServletRequest, ServletResponse)初始化,且传递过来的request是HttpServletRequest的实例,那么这个请求分发到HttpServletRequest.getRequestURI()返回的URI。否则当最后转发时当由容器转发到request的URI。

AsyncContext接口中的dispatch方法可被等待异步事件发生的应用程序调用。如果AsyncContext已经调用了complete()方法,必须抛出IllegalStateException异常。所有不同的dispatch方法会立即返回并且不会提交response。

request对象暴露给目标servlet的路径元素(path elements)必须反映AsyncContext.dispatch中指定的路径。

9.7.1 查询字符串

请求调度机制是在调度请求时负责聚焦(aggregating)查询字符串。

9.7.2 调度请求参数

使用AsyncContext的dispatch方法调用过的servlet能够访问原始请求的路径。

下面的request属性必须设置:

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的getRequestURI,、getContextPath、 getServletPath、getPathInfo、getQueryString方法的返回值相等,这些方法在从客户端接收到的request对象上调用,值传递给调用链中的第一个servlet对象。

这些属性通过转发servlet的request对象的getAttribut方法访问。请注意,即使在多个转发和相继的包含(subsequent includes)被调用的情况下,这些属性必须始终反映原始请求中的信息。


猜你喜欢

转载自jinnianshilongnian.iteye.com/blog/1752169