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
相关的参数只在include
或forward
调用期间适用。
参数优先级
请求调度器的使用
为了使用一个请求调度器,Servlet会调用RequestDispatcher
接口的include方法或forward方法。这些方法的参数可以是通过javax.servlet.Servlet
接口的服务方法传入的request
和response
参数,也可以是为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使用RequestDispatcher
的include
方法调用的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使用RequestDispatcher
的forward
方法调用的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
方法getRequestURI
、getContextPath
、getServletPath
、getPathInfo
、getQueryString
的返回值,分别在传递给从客户端接收请求的调用链中第一个Servlet对象的请求对象上调用。
这些属性可以通过请求对象上的getAttribute
方法从转发的servlet访问。请注意,这些属性必须始终反映原始请求中的信息,即使在调用多个转发和后续包含的情况下也是如此。
如果被转发的servlet是通过使用getNamedDispatcher
方法获得的,这些属性必须不被设置。
错误的处理
如果作为请求分派器目标的Servlet抛出了一个运行时异常或一个ServletException
或IOException
类型的检查异常,它应该被传播给调用的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 方法的参数
通过使用AsyncContext
的dispatch
方法调用的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
方法getRequestURI
、getContextPath
、getServletPath
、getPathInfo
、getQueryString
的返回值,分别在传递给调用链中第一个接收客户端请求的Servlet对象的请求对象上调用。
这些属性可以通过请求对象上的getAttribute
方法从被派遣的servlet访问。请注意,这些属性必须始终反映原始请求中的信息,即使是在调用多个调度的情况下。
以上是关于Servlet规范之转发请求的主要内容,如果未能解决你的问题,请参考以下文章