Servlet规范之The Request
Posted 顧棟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet规范之The Request相关的知识,希望对你有一定的参考价值。
The Request
文章是对 JSR-000340 JavaTM Servlet 3.1 Final Release的Java™ Servlet规范的翻译,尚未校准
文章目录
请求对象封装了来自客户端请求的所有信息。在HTTP协议中,这些信息在HTTP头和请求的信息体中从客户端传输到服务器。
HTTP协议参数
Servlet的请求参数是由客户端发送至Servlet容器的字符串,作为其请求的一部分。当请求是一个HttpServletRequest
对象,并且符合第24页 "When Parameters Are Available"中规定的条件时,容器会从URI查询字符串和POST-ed数据中填充参数。
参数被存储为一组name-value对。对于任何给定的参数名称,可以存在多个参数值。ServletRequest
接口的下列方法可用于访问参数。
- getParameter
- getParameterNames
- getParameterValues
- getParameterMap
getParameterValues
方法返回一个字符串对象数组,其中包含与参数名称相关的所有参数值。从getParameter
方法返回的值必须是getParameterValues
返回的String
对象阵列中的第一个值。getParameterMap
方法返回请求的参数的java.util.Map
,它包含作为键的名称和作为映射值的参数值。
来自查询字符串和帖子正文的数据被汇总到请求参数集。查询字符串的数据会在帖子正文的数据之前呈现。例如,如果一个请求的查询字符串为a=hello,帖子正文为a=goodbye&a=world
,那么产生的参数集将被排序为a=(hello, goodbye, world)
。
作为GET请求的一部分的路径参数(如HTTP 1.1所定义的)不被这些API所公开。它们必须从getRequestURI
方法或getPathInfo
方法返回的String
值中解析出来。
When Parameters Are Available
以下是必须满足的条件,然后才会将表单数据填充到参数集中。
- 该请求是一个HTTP或HTTPS请求。
- HTTP方法是POST。
- 内容类型是
application/x-www-form-urlencoded
。 - servlet对请求对象的
getParameter
系列方法进行了初始调用。
如果不满足这些条件,并且post form数据不包括在参数集中,那么post数据仍然必须通过请求对象的输入流提供给servlet。如果条件得到满足,POST数据将不再可用于直接从请求对象的输入流中读取。
文件上传
Servlet容器允许在数据以multipart/form-data
形式发送时上传文件。
如果满足以下任何一个条件,Servlet容器就会提供multipart/form-data
处理。
- 处理请求的servlet被注释为
@MultipartConfig
,定义在第8-70页的第8.1.5节"@MultipartConfig"。 - 部署描述符包含处理请求的Servlet的
multipart-config
元素。
如何提供multipart/form-data
类型的请求中的数据,取决于servlet容器是否提供multipart/form-data
处理:
-
如果servlet容器提供了
multipart/form-data
处理,数据将通过HttpServletRequest
中的下列方法提供:public Collection<Part> getParts()
public Part getPart(String name)
每个part都可通过
Part.getInputStream
方法访问头部,相关的内容类型和内容。对于以表单数据的
Content-Disposition
的部分,即使没有文件名,该部分的字符串值也将通过HttpServletRequest
上的getParameter
和getParameterValues
方法得到该部分的名称。 -
如果servlet容器不提供
multi-part/form-data
处理,数据将通过HttpServletReuqest.getInputStream
来获得。
Attributes
属性是与一个请求相关的对象。属性可以由容器设置,以表达无法通过API表达的信息,也可以由Servlet设置,以向另一个Servlet传递信息(通过RequestDispatcher
)。属性可以通过ServletRequest
接口的下列方法来访问:
- getAttribute
- getAttributeNames
- setAttribute
一个属性名称只能关联一个属性值。
以 java.
和javax.
开头的属性名被保留给本规范定义。同样,以sun.
、com.sun.
、oracle
和com.oracle
开头的属性名也被保留给Oracle公司定义。建议放在属性集中的所有属性都按照《Java编程语言规范》建议的反向域名惯例来命名包。
Headers
一个servlet可以通过HttpServletRequest
接口的以下方法访问HTTP请求的头信息:
- getHeader
- getHeaders
- getHeaderNames
getHeader
方法返回一个给定的头的名称。在一个HTTP请求中可以有多个同名的头,例如Cache-Control
头。如果有多个同名的头信息,getHeader
方法会返回请求中的第一个头信息。getHeaders
方法允许访问所有与特定头名称相关的头值,返回一个Enumeration
的字符串对象。
头信息可以包含 int
或 Date
数据的String
表示。HttpServletRequest
接口的下列方便方法提供了对这些格式之一的头数据的访问:
- getIntHeader
- getDateHeader
如果getIntHeader
方法不能将头的值翻译成int
,就会抛出NumberFormatException
。如果getDateHeader
方法不能将标题翻译成Date
对象,就会抛出IllegalArgumentException
。
Request Path 元素
服务请求的servlet的请求路径由许多重要部分组成。以下元素从请求URI路径中获得,并通过请求对象暴露:
- Context Path: 与
ServletContext
相关的路径前缀,该Servlet是其中的一部分。如果这个上下文是基于Web服务器的URL名称空间的 "default"上下文,这个路径将是一个空字符串。否则,如果该上下文没有基于服务器名称空间的根目录,那么该路径以一个/
字符开始,但不以一个/
字符结束。 - Servlet Path: 直接对应于激活该请求的映射的路径部分。这个路径以
/
字符开始,除非请求与/*
或" "模式匹配,在这种情况下,它是一个空字符串。 - PathInfo: 请求路径中不属于Context Path或Servlet Path的部分。如果没有额外的路径,它就是空的,或者是一个带
/
的字符串。
使用HttpServletRequest接口中的下面方法来访问这些信息:
- getContextPath
- getServletPath
- getPathInfo
需要注意的是,除了请求URI和路径部分的URL编码不同,下面的等式总是正确的:
requestURI = contextPath + servletPath + pathInfo
举几个例子来说明上述观点,请考虑以下几点:
TABLE 3-1 Example Context Set Up
Context | Path | /catalog |
---|---|---|
Servlet | Mapping | Pattern: /lawn/* Servlet: LawnServlet |
Servlet | Mapping | Pattern: /garden/* Servlet: GardenServlet |
Servlet | Mapping | Pattern: *.jsp Servlet: JSPServlet |
The following behavior is observed:
TABLE 3-2 Observed Path Element Behavior
Request Path | Path Elements |
---|---|
/catalog/lawn/index.html | ContextPath: /catalog ServletPath: /lawn PathInfo: /index.html |
/catalog/garden/implements/ | ContextPath: /catalog ServletPath: /garden PathInfo: /implements/ |
/catalog/help/feedback.jsp | ContextPath: /catalog ServletPath: /help/feedback.jsp PathInfo: null |
路径转换方法
在API中有两个方便的方法,允许开发者获得相当于特定路径的文件系统路径。这些方法是:
- ServletContext.getRealPath
- HttpServletRequest.getPathTranslated
getRealPath方法接受一个String
参数,并返回一个路径所对应的本地文件系统中的文件的String
表示。getPathTranslated
方法计算请求的pathInfo
的真实路径。
在Servlet容器无法为这些方法确定有效的文件路径的情况下,例如,当Web应用程序从归档文件、在本地无法访问的远程文件系统或在数据库中执行时,这些方法必须返回空。JAR文件的META-INF/resources
目录下的资源,只有在调用getRealPath()
时,容器已经将其从包含的JAR文件中解压,才必须考虑,在这种情况下,必须返回解压的位置。
Non Blocking IO
Web容器中的非阻塞请求处理有助于改善不断增长的对改进Web容器可扩展性的需求,增加Web容器可同时处理的连接数。Servlet容器中的非阻塞IO允许开发者在数据可用时读取数据,或在可能时写入数据。非阻塞IO只适用于Servlet和过滤器中的异步请求处理(如第2-10页第2.3.3.3节 "异步处理 "中的定义),以及升级处理(如第2-20页第2.3.3.5节 "升级处理 "中的定义)。否则,当调用ServletInputStream.setReadListener
或ServletOutputStream.setWriteListener
时,必须抛出一个IllegalStateException
。
The ReadListener
provides the following callback methods for non blocking IO
ReadListener
为非阻塞性IO提供以下回调方法:
ReadListener
onDataAvailable()
. 当可以从传入的请求流中读取数据时,onDataAvailable
方法会被调用到ReadListener
上。容器将在数据可被读取时第一次调用该方法。容器随后将调用onDataAvailable
方法,当且仅当ServletInputStream
上的isReady
方法(如下所述)返回false
。onAllDataRead()
. 当你完成了对注册了监听器的ServletRequest
的所有数据的读取时,onAllDataRead
方法被调用。onError(Throwable t)
. 如果在处理请求时有任何错误或异常,onError
方法会被调用。
Servlet容器必须以线程安全的方式访问ReadListener
中的方法。
除了上面定义的 ReadListener
之外,在ServletInputStream
类中还增加了以下方法:
ServletInputStream
boolean isFinished()
. 当所有与ServletInputStream
相关的请求数据被读取时,isFinished
方法返回true。否则它将返回false
。boolean isReady()
.isReady
方法返回true
,如果数据可以无阻塞地被读取。如果没有数据可以在不阻塞的情况下被读取,则返回 “false”。如果isReady返回false,调用read方法是非法的,必须抛出一个IllegalStateException
。void setReadListener(ReadListener listener)
. 设置上面定义的ReadListener
,使其被调用,以非阻塞的方式读取数据。一旦监听器与给定的ServletInputStream
相关联,容器就会在数据可以读取、所有数据都已读取或处理请求时出现错误时调用ReadListener
的方法。注册一个ReadListener将启动非阻塞的IO。此时切换到传统的阻塞式IO是非法的,必须抛出一个IllegalStateException
。在当前请求的范围内对setReadListener
的后续调用是非法的,必须抛出IllegalStateException
。
Cookies
HttpServletRequest
接口提供了getCookies
方法来获取请求中存在的cookies数组。这些cookie是在客户端发出的每个请求中从客户端发送到服务器的数据。通常情况下,客户端作为cookie的一部分发回的唯一信息是cookie名称和cookie值。当cookie被发送到浏览器时可以设置的其他cookie属性,如评论,通常不被返回。该规范还允许cookies为HttpOnly
cookies。HttpOnly
cookie向客户端表明,它们不应该被暴露给客户端脚本代码(除非客户端知道要寻找这个属性,否则它不会被过滤掉)。使用HttpOnly
cookies有助于减轻某些类型的跨站脚本攻击。
SSL Attributes
如果一个请求是通过安全协议(如HTTPS)传输的,这一信息必须通过ServletRequest
接口的isSecure
方法公开。Web容器必须向Servlet程序员公开以下属性:
TABLE 3-3 Protocol Attributes
Attribute | Attribute Name | Java Type |
---|---|---|
cipher suite | javax.servlet.request.cipher_suite | String |
bit size of the algorithm | javax.servlet.request.key_size | Integer |
SSL session id | javax.servlet.request.ssl_session_id | String |
如果有一个与请求相关的SSL证书,它必须由servlet容器暴露给servlet程序员,作为java.security.cert.X509Certificate
类型的对象数组,并通过javax.servlet.request.X509Certificate
的ServletRequest
属性访问。
这个数组的顺序被定义为按照信任度的升序排列。链中的第一个证书是由客户设置的,下一个是用来验证第一个的,以此类推。
国际化
客户端可以选择向网络服务器表明他们希望响应的语言。这个信息可以从客户端使用Accept-Language
标头和HTTP/1.1规范中描述的其他机制来传达。ServletRequest
接口中提供了以下方法来确定发送者的首选语言。
- getLocale
- getLocales
getLocale
方法将返回客户想要接受的内容的首选地区。参见RFC 2616 (HTTP/1.1)第14.4节,了解更多关于如何解释Accept-Language
头以确定客户端的首选语言。
getLocales
方法将返回一个Locale
对象的枚举,按照从首选语言开始的递减顺序,指出客户可以接受的语言。
如果客户没有指定首选的locale,getLocale
方法返回的locale必须是servlet容器的默认locale,getLocales
方法必须包含默认locale的一个Locale
元素的枚举。
请求数据的编码
目前,许多浏览器并不随Content-Type
头发送 char
编码修饰符,这就使读取HTTP请求的字符编码的确定成为可能。如果客户端请求没有指定编码,容器用来创建请求阅读器和解析POST数据的默认编码必须是 “ISO-8859-1”。然而,为了向开发者表明,在这种情况下,客户端未能发送字符编码,容器会从getCharacterEncoding
方法中返回null
。
如果客户端没有设置字符编码,而请求数据的编码与上述的默认编码不同,就会发生中断。为了补救这种情况,一个新的方法setCharacterEncoding(String enc)
已经被添加到ServletRequest
接口中。开发者可以通过调用这个方法来覆盖由容器提供的字符编码。它必须在解析任何职位数据或从请求中读取任何输入之前被调用。一旦数据被读取,调用此方法将不会影响编码。
请求对象的生命周期
每个请求对象只在servlet的service
方法的范围内有效,或者在过滤器的doFilter
方法的范围内有效,除非组件的异步处理被启用,并且startAsync
方法被调用到请求对象上。在异步处理发生的情况下,请求对象仍然有效,直到complete
在AsyncContext
上被调用。容器通常会回收请求对象,以避免创建请求对象的性能开销。开发者必须意识到,不建议在上述范围之外维护对startAsync
未被调用的请求对象的引用,因为这可能会产生不确定的结果。
在升级的情况下,上述情况仍然适用。
以上是关于Servlet规范之The Request的主要内容,如果未能解决你的问题,请参考以下文章
The process of container handles the servlet request