Tomcat源码分析--ServletRequest.getParameterValue分析,Request字符集&QueryStringEncoding

[color=red]总结:[/color]
HTTP GET方式
无forward操作,解码只受Connector参数影响(URIEncoding或者UseBodyEncondig)
有forward操作,解码只受HTTP Header中ContentType指定的字符集或者Filter设置影响
多次forward的话,forward后,第一次从请求取值后,tomcat进行了参数解码,后面就不会再次解码(即多次forward的情况,只有2次解码动作,forward之前和forward之后第一次从request取值)

HTTP GET方式
不管有无forward操作,解码只受HTTP Header中ContentType指定的字符集或者Filter设置影响(第一次从request取值时对应应用环境下的Filter)

[color=red]request.getParameterValues和request.getParameter[/color]的逻辑是类似的,都是看相应的Request参数是否已经转换过[color=green](调用getParameter, getParameterValues, getParameterMap, getParameterNames这4个方法都会触发参数转换操作)[/color],没有那么调用相应的转换程序,否则就直接操作转换好的paramters(HashMap)

ApplicationDispatcher是RequestDispatcher接口的final标准实现,允许请求forward到其他资源进行服务(include也使用该类)。这个实现是在Application应用程序级别的Servlet中对请求和响应进行包装(ServletRequest,ServletResponse或者ServletRequestWrapper,ServletResponseWrapper)
参考:[url=http://docjar.com/docs/api/org/apache/catalina/core/ApplicationDispatcher.html]final class: ApplicationDispatcher [/url]

[color=red]RequestDispatcher.forward前使用的是,RequestFacade;forward之后使用的是ApplicationHttpRequest。[/color]它们对用来给请求解码的编码的默认值处理不同,具体参考如下。而[color=green]如果在forward之前,调用过request.getParameter方法来取值,那么forward后,CoyteRequest内的信息可能被解码,但是当前请求ApplicationHttpRequest对应的参数还没有解码!2部分参数会合成并且当前请求ApplicationHttpRequest对应的参数是放在前面的![/color][color=red]注意:此时重新解码的参数是Get方式的QueryString的参数,POST提交的参数还是在RequestFacade进行解码!!![/color]

forward之前从RequestFacade取值
1,调用request.getParameterValues方法
2,对应org.apache.catalina.connector.[color=red]RequestFacade[/color]类的getParameterValues方法(RequestFacade是一个HttpServletRequest实现类,他包含一个叫Coyote request的属性,具体请求执行内容由具体的Coyote request决定)
3,调用org.apache.catalina.connector.Request的getParameterValues方法,[color=red]如果第一次取调用该方法[/color](即还没有做过参数转换----把QueryString或者POST上来的比特数组通过设定的编码转成真正的值),[color=red]那么进行参数转换操作,否则直接从已经转换好的参数列表中提取相应参数的值[/color]
4,参数转换:
[list]
[*]a.取得Request字符集enc:1,看请求本身是否已经被设置了字符集(通过request.setCharacterEncoding设置),如果有直接返回,如果没有,那么根据请求的Content-Type,看Content-Type中是否通过charset=xxx设置了字符集,有就起作用,没有就返回null
[*]b.取得Connect参数UseBodyEncodingForURI对应的值
[*]c.如果a)步骤取得的Request字符集enc非空,那么Parameters字符集等于Request字符集,如果UseBodyEncodingForURI为true,那么QueryString解码使用的字符集QueryStringEncoding的值也设置为请求字符集(和Parameters一致)
[*]d.如果a)步骤取得的Request字符集enc为空,那么Parameters字符集等于默认的字符集ISO-8859-1,如果UseBodyEncodingForURI为true,那么QueryString解码使用的字符集QueryStringEncoding的值也设置为默认的字符集ISO-8859-1(和Parameters一致)
[*]e.对QueryString所传递的参数进行解码操作(根据QueryStringEncoding)
[*]f.看HTTP METHOD是否等于POST,同时看Content-Type是否以[color=red]application/x-www-form-urlencoded[/color]开始,是的话,对通过POST方式上传的比特数组byte[] postData,用d)步骤取得的Parameters字符集进行解码(如果没有值,就默认用ISO-8859-1),并把解码后的参数值保存到参数列表中等待下次复用(只解码一次!!!)
[/list]

forward之后从ApplicationHttpRequest取值[color=green]注意,forward之后,这个Request中解码的只有QueryString的参数,且从request取值的时候刚解码的参数优先级高(数组下标),而post提交的参数,会直接调用ApplicationHttpRequest中嵌套的RequestFacade的相应方法取值,即Post方式提交的参数的解码,受到forward之前请求的相关环境的影响!!![/color]
1,调用request.getParameterValues方法
2,对应8, org.apache.catalina.core.[color=red]ApplicationHttpRequest[/color]类的getParameterValues方法(ApplicationHttpRequestS有一个ServletRequest的属性,而RequestFacade是ServletRequest的一个属性),[color=red]由此可以看出,对于参数取值,forward后的Request多一层包装。[/color]
3,调用org.apache.catalina.core.ApplicationHttpRequest的getParameterValues方法,[color=red]如果参数还没有被转换过那么进行参数转换操作,否则直接从已经转换好的参数列表中提取相应参数的值[/color]
4,参数转换:
[list]
[*]a.取得已有的参数(即从当前request中取得CoyteRequest中已有的参数,[color=red]注意:如果一个url前面做过forward的话,并且在forward之前已经从Request取过值的话,CoyteRequest中的取得的参数是已经转换过的!!!但是ApplicationHttpRequest本身的Parameter并没有被转换过!!![/color])代码如下:parameters = new HashMap();parameters = copyMap(getRequest().getParameterMap());
[*]b.调用mergeParameters方法,把ApplicationHttpRequest自己的参数QueryString对应的参数值解码出来,并和CoyteRequest中已有的参数合并,刚解码出来的参数放到数组前面,这样你使用Request.getParametr来取字段的值的时候,取出来的是刚解码的值,而如果用取数组的方法,那么取出来是整个数组。

ApplicationHttpRequest解码自己参数的逻辑:
取得Request字符集,如果取不到,就直接使用ISO-8859-1字符集来解码。然后调用RequestUtil.parseParameters(queryParameters, queryParamString, encoding)来进行解码操作。[color=red]表明此时,Connector的参数UseBodyEncodingForURI和URIEncoding并没有影响QueryString的解码[/color]。
[/list]
5,[color=red]总结:[/color]
[list]
[*]a.[color=green]QueryStringEncoding[/color]:用来解码[color=red]QueryString[/color]信息
[*]b.[color=green]Request字符集[/color]:[color=red]Content-Type中的字符集影响的是Request字符集,并不影响QueryStringEncoding,间接影响Parameters字符集[/color]
[*]c.[color=green]Parameters字符集[/color]:用来解码[color=red]POST参数【比特数组】[/color]时使用的字符集,如果Request字符集非空,那么Parametr是字符集=Request字符集,否则等于默认字符集ISO-8859-1。Parameters字符集用来解码POST DATA对应的比特数组(解码后在JVM中以Unicode的形式存在)
[*]d.参考[url=http://desert3.iteye.com/admin/blogs/1419956]Tomcat源码分析--HTTP,AJP请求内部处理流程[/url],可以看出对于RequestFacade请求,QueryStringEncoding的值首先从Connector中的参数URIEncoding中取,同时参考下面的说明,可知useBodyEncodingForURI的优先级 大于URIEncoding
[*]e.Request字符集:如果没有通过request.setCharacterEncoding方法设置字符集,那么默认从Content-Type中提取charset=xxx的值,如果通过request.setCharacterEncoding方法设置了新的字符集,那么新的字符集会覆盖Content-Type中的字符集
[*]f.如果设置了Connector的参数useBodyEncodingForURI=true,那么把QueryStringEncoding值设置为和Request字符集相同!
[/list]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值