5.6 例子:HTTP参数处理
Last updated
Last updated
在服务器收到一个HTTP请求后,服务器需要访问请求中的一些信息。处理图5.1中请求的代码可能需要知道photo_id
参数的值。参数可以在请求的第一行指定(图5.1中的photo_id
),有时也可以在请求体中指定(图5.1中的comment
和priority
)。每个参数都有一个名称和一个值。参数的值使用一种特殊的编码,称为URL编码(URL encoding);例如,在图5.1中comment
的值中,“+”被用来代表一个空格字符,而“%21”被用来代替“!”。为了处理一个请求,服务器将需要一些参数的值,并希望它们是未编码的形式。
大多数的学生项目在参数处理方面做出了两个很好的选择。首先,他们认识到服务器应用程序并不关心一个参数是在请求行还是在请求体中指定的,所以他们向调用者隐藏了这种区别,并将两个位置的参数合并在一起。其次,他们隐藏了关于URL编码的知识:HTTP解析器在将参数值返回给Web服务器之前会对其进行解码,因此图5.1中的comment
参数的值会被返回为“What a cute baby!”,而不是“what+a+cute+baby%21”)。在这两种情况下,信息隐藏都导致使用HTTP模块的代码的API更加简单。
然而,大多数学生使用的返回参数的接口过于浅,这导致他们丧失了信息隐藏的机会。大多数项目使用一个HTTPRequest
类型的对象来保存解析后的HTTP请求,而HTTPRequest
类只有一个类似下面这样的方法来返回参数:
该方法返回的不是一个参数,而是一个内部用来存储所有参数的Map
的引用。这个方法是浅的,它暴露了HTTPRequest
类用来存储参数的内部表示。对该表示法的任何改变都将导致对接口的改变,这将需要对所有调用者进行修改。当实现被修改时,这些变化往往涉及关键数据结构的表示方法的变化(例如,为了提高性能)。因此,尽可能地避免暴露内部数据结构是很重要的。这种方法也给调用者带来了更多的工作:调用者必须首先调用getParams
,然后它必须调用另一个方法来从Map
中获取特定的参数。最后,调用者必须意识到,他们不应该修改getParams
返回的Map
,因为这将影响HTTPRequest
的内部状态。
下面是一个更好的检索参数值的接口:
getParameter
以字符串形式返回参数值。它提供了一个比上面的getParams
更深的接口;更重要的是,它隐藏了参数的内部表示。 getIntParameter
将一个参数的值从HTTP请求中的字符串形式转换为一个整数(例如,图5.1中的photo_id
参数)。这就省去了调用者单独请求字符串到整数的转换,并对调用者隐藏了这一机制。如果需要,可以为其他数据类型定义额外的方法,如getDoubleParameter
。(如果所需的参数不存在,或者它不能被转换为所要求的类型,所有这些方法都会抛出异常;在上面的代码中省略了异常声明)。