request对象封装了来自客户端的所有请求信息。在HTTP协议中,客户端发给服务端的所有信息都是通过request对象的请求头和请求体来传送的。
SRV.4.1 HTTP协议参数
servlet的请求参数作为客户端请求的一部分都是以字符串形式传给servlet容器。当请求信息使用HttpServletRequest对象时,如果满足可用参数的必需条件,那么容器就会传送URI的查询参数和POST的表单数据。
参数以名值对方式存储,而且一个参数名可以对应多个参数值。ServletRequest接口的以下4个方法用于访问这些参数信息:
• getParameter
• getParameterNames
• getParameterValues
• getParameterMap
getParameterValues方法查询一个参数名对应的所有参数值,然后以String数组返回。而getParameter方法与此类似,只不过getParameter只返回getParameterValues方法查询出来的String数组的第一个值而已。getParameterMap方法以Map方式返回所有的请求参数,当然,这个Map以参数名为key,参数值为对应的value。
从query字串和post提交的请求体获得的所有请求数据都会包装进请求参数集合中。query字串的数据优先性要高于post提交的数据。例如,客户端在地址栏的query参数有一个a=hello,而以post提交的请求体参数中有一个a=goodbye$a=world,那么最终服务端包装好的参数结果会排序为a=(hello,goodbye,world)。
作为GET请求的一部分的路径参数不会被当前API规范处理和显示。他们必须通过getRequestURI或者getPathInfo方法返回的String结果来解析。
SRV.4.1.1 参数可用性
以下4点是使用post方式提交请求数据时必须满足的先决条件:
1. HTTP请求或者是HTTPS请求。
2. HTTP的请求方法为POST方式。
3. 内容类型是application/x-www-form-urlencoded。
4. servlet已经在请求对象上初始化调用了getParameter方法。
若不满足上述条件,post提交的表单数据不会包含在参数集中,但post的数据本身仍然可以通过请求对象的输入流进行访问。若满足上述条件,post提交的表单数据就不能再通过请求对象的输入流进行直接访问了。
SRV.4.2 属性
Attributes是请求的关联对象,Attributes可以被容器用于标识Servlet API无法表达出来的信息,或者用于多个servlet之间相互沟通交流数据。Attributes可通过ServletRequest接口的下述方法进行访问:
• getAttribute
• getAttributeNames
• setAttribute
一个属性名只能对应一个属性值。以“java.”和“javax.”开头的属性名已经预留给Servlet规范本身。同样的,“sun.”和“com.sun”也已经预留给Sun微系统公司。建议所有的属性都是用倒置域名或Java的包命名规则来进行属性命名,这样可以确保属性名的唯一性。
SRV.4.3 Headers
servlet通过HttpServletRequest接口的下述方法访问HTTP请求的头信息:
• getHeader
• getHeaders
• getHeaderNames
getHeader返回指定名字的header信息。一个头名可以对应多个头值,和request类似。若有多个值,getHeader只返回第一个请求头,而getHeaders则可以返回所有的头信息(以String对象的枚举返回)。
头包含了int和Date类型的字符串表示。通过HttpServletRequest的以下几个方法可以访问对应的请求头数据:
• getIntHeader
• getDateHeader
如果getIntHeader方法不能把header转换为int类型,就会抛出NumberFormatException。同理,若getDateHeader方法不能正常转化Date类型,就会抛出IllegalArgumentExcetion。
SRV.4.4 请求路径相关的元素
请求路径由多段重要信息组合而成。以下元素有请求的URI获得并由request对象展示:
1. Context Path:和ServletContext关联的路径前缀。如果应用的上下文是Web服务URL命名空间的默认上下文,那么Context Path就是空的。否则,它就以斜杠“/”开始以其他非斜杠字符结束。
2. Servlet Path:这段路径对应着处理请求的映射路径,它始于斜杠“/”。如果请求匹配于“/*”规则,那么这时的Servlet Path会是空字串。
3. PathInfo:这段既不是Context Path的一部分,也不是Servlet Path的一部分。它要么为空,要么就是以斜杠“/”作为前导字符的一段字符串。
HttpServletRequest接口的下述3个方法用于访问这些信息:
• getContextPath
• getServletPath
• getPathInfo
记住这么一点:除非请求的URI和路径部分的编码不同,否则以下等式永远成立:
requesetURI = contextPath + servletPath + pathInfo。
为了理解这点,思考以下例子:
表1:上下文设置示例
Context Path |
/catalog |
Servet Manpping |
Pattern: /lawn/* |
Servlet Mapping |
Pattern: /garden/* |
Servet Mapping |
Pattter: *.jsp |
表2:路径元素解析
/catalog/lawn/index.html |
ContextPath: /catalog ServletPath: /lawn PathInfo: /index.html |
/catalog/garden/implements/ | ContextPath: /catalog ServletPath: /garden PathInfo: /implements/ |
/catalog/help/feedbak.jsp | ContextPath: /catalog ServletPath: /help/feedback.jsp PathInfo: null |
SRV.4.5 路径转换的方法
API里有两个便捷方法可以让开发人员获取Servlet对应的文件系统真实路径:
• ServletContext.getRealPath
• HttpServletRequest.getPathTranslated
getRealPath方法接收一个String参数,然后返回这个参数对应的本地文件系统上的文件路径。getPathTranslated方法计算请求中的pathInfo对应的真实路径。
某些情况下Servlet容器无法获知这些方法对应的可用文件路径,例如当web应用是从压缩包中执行时、来自本地无法访问的远程文件系统时、或者数据库时,这些方法都会返回null。
SRV.4.6 Cookies
HttpServletRequest接口提供了getCookies方法去获取请求对象的cookies数组,这些cookies是每次客户端发送请求时带到服务端的。典型情况下,发回客户端的cookies中仅有的信息就是cookie名值对。其他的cookie属性也可以在返回给浏览器时设置,例如注释之类的,当然通常是不会有这些数据的。
SRV.4.7 SSL属性
如果发送的请求使用了HTTPS等安全协议,那调用ServletRequest接口的isSecure方法时,请求信息必须是安全的。web容器必须维护以下属性:
表3:协议相关属性
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授权认证,那servlet容器必须展示给开发人员一个java.security.cert.X509Certificate对象数组,并且通过ServletRequest的javax.servlet.request.X509Certificate属性可访问这些授权。
这个数组以授信级联关系作为排序层次,授信链的第一级认证由客户端设置,下一级则为前一级认证做授权,以此类推。
SRV.4.8 国际化
客户端可以指定web服务以哪种语言返回响应信息。这个语言设置由客户端的Accept-Language请求头指明。ServletRequest接口的下述方法用于侦测应答时需要的本地化设置:
• getLocale
• getLocales
getLocale方法返回客户端更喜欢使用的locale。getLocales方法则返回一个Locale的枚举对象,依喜好级别依次列举客户端最想要的、可以接受的locale。
若客户端没有指定这些,getLocale方法就必须返回servlet容器的默认locale,而getLocales方法则必须返回包含默认locale的枚举对象。
SRV.4.9 请求数据的编码
当下很多浏览器都并不指定编码格式,由服务程序自动决定读取请求数据时的编码方法。若客户端并未指定编码格式,那容器读取请求头和解析POST数据体时必须统一使用“ISO-8859-1”编码。但是,即使servlet容器默认都统一使用了“ISO-8859-1”,getCharacterEncoding方法也必须返回null,以明确告知开发人员此时客户端请求没有指定编码格式。
如果客户端未指定字符编码,而解析请求数据时又用了不同的编码规则,那就会出现乱码问题。为解决这种问题,ServletRequest接口新加了一个setCharacterEncoding(String enc)方法。开发人员通过它可以重设容器的编码方式。需要强调的是,这个方法必须在解析或读取任何请求数据和输入流之前被调用,否则不会生效。
SRV.4.10 请求对象的生命周期
每个请求对象只在当前servlet的service方法域内可用,或者是在filter的doFilter方法域内可用。通常容器回收请求对象主要是为了避免创建新请求对象时的性能开销。开发人员必须避免在上述作用域外调用请求对象,否则极易导致不可预期的执行结果。