3.4 请求
请求对象封装了客户端请求的所有信息。在HTTP协议中,这些信息包含在从客户端发送到服务器请求的HTTP头部和消息体中。
3.4.1 HTTP协议参数
Servlet的请求参数以字符串的形式作为请求的一部分从客户端发送到Servlet容器。当请求是一个HttpServletRequest对象且符合“参数可用时”描述的条件时,容器从URI查询字符串和POST数据中填充参数。参数以一系列的名-值对(name-value)的形式保存。任何给定的参数的名称可存在多个参数值。ServletRequest接口的以下方法可访问这些参数:
- getParameter
- getParameterNames
- getParameterValues
- getParameterMap
getParameterValues方法返回一个String对象的数组,包含了与参数名称相关的所有参数值。
getParameter方法的返回值必须是getParameterValues方法返回的String对象数组中的第一个值。
getParameterMap方法返回请求参数的一个java.util.Map对象,其中以参数名称作为Map键,参数值作为Map值。
查询字符串和POST请求的数据被汇总到请求参数集合中。查询字符串数据放在POST数据之前。例如,请求由查询字符串a=hello和POST数据a=goodbye&a=world组成,得到的参数集合顺序将是a=(hello, goodbye, world)。
这些API不会暴露GET请求(HTTP 1.1所定义的)的路径参数。它们必须从getRequestURI方法或getPathInfo方法返回的字符串值中解析。
post表单数据填充到参数集(Parameter Set)前必须满足以下条件:
- 该请求是一个HTTP或HTTPS请求。
- HTTP方法是POST。
- 内容类型是application/x-www-form-urlencoded。
- 该Servlet已经对请求对象的任意getParameter方法进行了初始调用。
如果不满足这些条件,而且参数集中不包括post表单数据,那么Servlet必须可以通过请求对象的输入流得到post数据。如果满足这些条件,那么从请求对象的输入流中直接读取post数据将不再有效。
3.4.2 属性
属性是与请求相关联的对象。属性可以由容器设置来表达信息,否则无法通过API表示,或者由Servlet设置将信息传达给另一个Servlet(通过RequestDispatcher)。属性通过ServletRequest接口中的以下方法来访问:
- getAttribute
- getAttributeNames
- setAttribute
一个属性名称只能关联一个属性值。
3.4.3 请求头
通过下面的HttpServletRequest接口方法,Servlet可以访问HTTP请求的头信息:
- getHeader
- getHeaders
- getHeaderNames
getHeader方法返回给定头名称的头。多个头可以具有相同的名称,例如HTTP请求中的Cache-Control头。如果多个头的名称相同,getHeader方法就返回请求中的第一个头。getHeaders方法允许访问所有与特定头名称相关的头值,返回一个String对象的Enumeration(枚举)。
头可包含String形式的Int或Date数据。HttpServletRequest接口提供如下方法访问这些类型的头数据:
- getIntHeader
- getDateHeader
如果getIntHeader方法不能转换为Int的头值,就抛出NumberFormatException异常。如果getDateHeader方法不能把头转换成一个Date对象,就抛出IllegalArgumentException异常。
3.4.4 请求路径元素
引导Servlet服务请求的请求路径由许多重要部分组成:
URI = Context Path + Servlet Path + PathInfo
其中:
- Context Path:与ServletContext相关联的路径前缀是这个Servlet的一部分。如果这个上下文是基于Web服务器的URL命名空间的“默认”上下文,那么这个路径将是一个空字符串。否则,如果上下文不是基于服务器的命名空间,那么这个路径以“/”字符开始,但不以“/”字符结束。
- Servlet Path:路径部分直接与激活请求的映射对应。这个路径以“/”字符开头,如果请求与“/*”或“”模式匹配,在这种情况下,它是一个空字符串。
- PathInfo:请求路径的一部分,不属于Context Path或Servlet Path。如果没有额外的路径,它要么是null,要么是以“/”开头的字符串。使用HttpServletRequest接口中的以下方法来访问这些信息:
getContextPath
getServletPath
getPathInfo
表3-1展示了请求路径元素的使用例子。
表3-1 请求路径元素的使用例子
3.4.5 路径转换方法
在Servlet API中有两个方便的方法,允许开发者获得与某个特定的路径等价的文件系统路径。这两个方法是:
- ServletContext.getRealPath
- HttpServletRequest.getPathTranslated
getRealPath方法需要一个String参数,并返回一个String形式的路径,这个路径对应一个在本地文件系统上的文件。getPathTranslated方法推断出请求的pathInfo的实际路径。
这些方法在Servlet容器无法确定一个有效的文件路径的情况下返回null,比如Web应用程序不能访问远程文件系统上的本地文件。JAR文件中META-INF/resources目录下的资源只有当调用getRealPath()方法时才认为容器已经从包含它的JAR文件中解压,在这种情况下必须返回解压缩后的位置。
3.4.6 请求数据编码
目前,很多HTTP请求并不一定会在Content-Type头上设置字符编码限定符。如果客户端请求没有指定请求默认的字符编码,那么容器用来创建请求读取器和解析POST数据的编码必须是ISO-8859-1。
如果客户端没有设置字符编码,并使用不同的编码来编码请求数据,而不是使用上面描述的默认的字符编码,那么可能会发生问题。为了弥补这种情况,开发人员可以通过下面几种方法来覆盖由容器提供的字符编码:
- *ServletContext上提供了setRequestCharacterEncoding(String enc)。
- web.xml中提供了元素。
- ServletRequest接口上提供了setCharacterEncoding(String enc)。
必须在解析任何post数据或从请求读取任何输入之前调用上述方法。上述方法一旦调用,将不会影响已经读取的数据的编码。