tomcat容器下 http 请求参数中特殊字符(+、&、%)的问题

一、现象

 大家在java web 开发过程中,应该遇到过请求参数中有特殊字符导致后台获取参数时异常的情况。

     参数中有 + : 比如参数是 voteless+cz ,在后台用 request.getParameter(); 获取时,发现变成了 voteless cz。就是 + 变成了 空格;

     参数中有& : 比如参数是  voteless&cz,在后台用 request.getParameter(); 获取时,发现变成了 voteless。就是 &和之后的参数会丢失。

     参数中有%: 比如参数是  voteless%cz,在后台用 request.getParameter(); 获取时,发现变成了 voteless�。%和后面的两个字符会变成乱码

     参数中有%: 比如参数是  voteless%c,在后台用 request.getParameter(); 获取时,发现是null。获取不到

 

二、原因

      原因是tomcat容器会丢对请求的参数(QueryString)进行类似 URLDecoder.decode的操作(GET和POST的请求都会,POST是 application/x-www-form-urlencoded )。

      1、&问题

         大家都知道&的目的是分隔 key=value。而value中有& 的话,其实很自然可以想到value中 & 后面的字符串会丢失,大家看如下的源码片段就明白了。

      org.apache.tomcat.util.http.Parameters 的 processParameters(byte bytes[], int start, int len, Charset charset) 方法

 

while(pos < end) {
    int nameStart = pos;
    int nameEnd = -1;
    int valueStart = -1;
    int valueEnd = -1;

    boolean parsingName = true;
    boolean decodeName = false;
    boolean decodeValue = false;
    boolean parameterComplete = false;

    do {
        switch(bytes[pos]) {
            case '=':
                if (parsingName) {
                    // Name finished. Value starts from next character
                    nameEnd = pos;
                    parsingName = false;
                    valueStart = ++pos;
                } else {
                    // Equals character in value
                    pos++;
                }
                break;
            case '&':
                if (parsingName) { // 重点在这个地方,value中&后面的字符串会当做是没有value的key
                    // Name finished. No value.
                    nameEnd = pos;
                } else { 
                    // Value finished
                    valueEnd  = pos;
                }
                parameterComplete = true;
                pos++;
                break;
            case '%':
            case '+':
                // Decoding required
                if (parsingName) {
                    decodeName = true;
                } else {
                    decodeValue = true;
                }
                pos ++;
                break;
            default:
                pos ++;
                break;
        }
    } while (!parameterComplete && pos < end);

    if (pos == end) {
        if (nameEnd == -1) {
            nameEnd = pos;
        } else if (valueStart > -1 && valueEnd == -1){
            valueEnd = pos;
        }
    }

 

 

 

      2、+和 % 问题

 

         上面提到tomcat会对参数进行解码,解码部分的源码如下  org.apache.tomcat.util.buf.UDecoder 的 String convert(String str, boolean query)

while (strPos < strLen) {
            int laPos;        // lookahead position

            // look ahead to next URLencoded metacharacter, if any
            for (laPos = strPos; laPos < strLen; laPos++) {
                char laChar = str.charAt(laPos);
                if ((laChar == '+' && query) || (laChar == '%')) {
                    break;
                }
            }

            // if there were non-metacharacters, copy them all as a block
            if (laPos > strPos) {
                dec.append(str.substring(strPos,laPos));
                strPos = laPos;
            }

            // shortcut out of here if we're at the end of the string
            if (strPos >= strLen) {
                break;
            }

            // process next metacharacter
            char metaChar = str.charAt(strPos);
            if (metaChar == '+') {
                dec.append(' ');
                strPos++;
                continue;
            } else if (metaChar == '%') {
                // We throw the original exception - the super will deal with
                // it
                //                try {
                char res = (char) Integer.parseInt(
                        str.substring(strPos + 1, strPos + 3), 16);
                if (noSlash && (res == '/')) {
                    throw new IllegalArgumentException("noSlash");
                }
                dec.append(res);
                strPos += 3;
            }
        }

 

 

 

      如上代码可以很明显看到 + 为什么变成了 空格;%部分可以看到代码截取%后的两位字符,然后放到StringBuilder,自如如上面例子中 voteless%cz,会将cz 以16进制转为 char ,得到的是怪怪的字符;如果是 voteless%c ,%后面只有一位,就会导致异常,使得获取不到value值(null)。

 

  

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值