• [转]详细解析ASP.NET中Request接收参数乱码原理


    起因:

    今天早上被同事问了一个问题:说接收到的参数是乱码,让我帮着解决一下。

    实际情景:

    同事负责的平台是Ext.js框架搭建的,web.config配置文件里配置了全局为“GB2312”编码:

    <globalization requestEncoding="gb2312" responseEncoding="gb2312" fileEncoding="gb2312" culture="zh-CN"/>

    当前台提交“中文文字”时,后台用Request.QueryString[
    "xxx"]接收到的是乱码。

    无论用System.Web.HttpUtility.UrlDecode(
    "xxx","编码类型")怎么解码都无效。

    原理说明:

    1:首先确定的是:客户端的url参数在提交时,Ext.js会对其编码再提交,而客户端的编码默认是utf-8编码

    客户端默认有三种编码函数:escape() encodeURI() encodeURIComponent()

    2:那为什么用Request.QueryString["xxx"]接收参数时,收到的会是乱码?

    为此,我们必须解开Request.QueryString的原始处理逻辑过程

    我们步步反编绎,

    2.1:看QueryString属性的代码:

    public NameValueCollection QueryString
    {
        
    get
        {
            
    if (this._queryString == null)
            {
                
    this._queryString = new HttpValueCollection();
                
    if (this._wr != null)
                {
                    
    this.FillInQueryStringCollection();//重点代码切入点
                }
                
    this._queryString.MakeReadOnly();
            }
            
    if (this._flags[1])
            {
                
    this._flags.Clear(1);
                ValidateNameValueCollection(
    this._queryString, "Request.QueryString");
            }
            
    return this._queryString;
        }
    }

    2.2:切入 FillInQueryStringCollection()方法

    private void FillInQueryStringCollection()
    {
        
    byte[] queryStringBytes = this.QueryStringBytes;
        
    if (queryStringBytes != null)
        {
            
    if (queryStringBytes.Length != 0)
            {
                
    this._queryString.FillFromEncodedBytes(queryStringBytes, this.QueryStringEncoding);
            }
        }
    //上面是对流字节的处理,即文件上传之类的。
        else if (!string.IsNullOrEmpty(this.QueryStringText))
        {
            
    //下面这句是对普通文件提交的处理:FillFromString是个切入点,编码切入点是:this.QueryStringEncoding
            this._queryString.FillFromString(this.QueryStringText, truethis.QueryStringEncoding);
            
        }
    }

    2.3:切入:QueryStringEncoding

    internal Encoding QueryStringEncoding
    {
        
    get
        {
            Encoding contentEncoding 
    = this.ContentEncoding;
            
    if (!contentEncoding.Equals(Encoding.Unicode))
            {
                
    return contentEncoding;
            }
            
    return Encoding.UTF8;
        }
    }
    //点击进入this.ContentEncoding则为:
    public Encoding ContentEncoding
    {
        
    get
        {
            
    if (!this._flags[0x20|| (this._encoding == null))
            {
                
    this._encoding = this.GetEncodingFromHeaders();
                
    if (this._encoding == null)
                {
                    GlobalizationSection globalization 
    = RuntimeConfig.GetLKGConfig(this._context).Globalization;
                    
    this._encoding = globalization.RequestEncoding;
                }
                
    this._flags.Set(0x20);
            }
            
    return this._encoding;
        }
        
    set
        {
            
    this._encoding = value;
            
    this._flags.Set(0x20);
        }
    }

    说明:

    从QueryStringEncoding代码得出,系统默认会先取globalization配置节点的编码方式,如果取不到,则默认为UTF-8编码方式

    2.4:切入  FillFromString(string s, bool urlencoded, Encoding encoding)

    代码有点长,就折叠起来了
    internal void FillFromString(string s, bool urlencoded, Encoding encoding)
    {
        
    int num = (s != null? s.Length : 0;
        
    for (int i = 0; i < num; i++)
        {
            
    int startIndex = i;
            
    int num4 = -1;
            
    while (i < num)
            {
                
    char ch = s[i];
                
    if (ch == '=')
                {
                    
    if (num4 < 0)
                    {
                        num4 
    = i;
                    }
                }
                
    else if (ch == '&')
                {
                    
    break;
                }
                i
    ++;
            }
            
    string str = null;
            
    string str2 = null;
            
    if (num4 >= 0)
            {
                str 
    = s.Substring(startIndex, num4 - startIndex);
                str2 
    = s.Substring(num4 + 1, (i - num4) - 1);
            }
            
    else
            {
                str2 
    = s.Substring(startIndex, i - startIndex);
            }
            
    if (urlencoded)//外面的传值默认是true,所以会执行以下语句
            {
                
    base.Add(HttpUtility.UrlDecode(str, encoding), HttpUtility.UrlDecode(str2, encoding));
            }
            
    else
            {
                
    base.Add(str, str2);
            }
            
    if ((i == (num - 1)) && (s[i] == '&'))
            {
                
    base.Add(nullstring.Empty);
            }
        }
    }

    说明:

    从这点我们发现:所有的参数输入,都调用了一次:HttpUtility.UrlDecode(str2, encoding);

    3:结论出来了

    当客户端js对中文以utf-8编码提交到服务端时,用Request.QueryString接收时,会先以globalization配置的gb2312去解码一次,于是,产生了乱码。

    所有的起因为:

    1:js编码方式为urt-8

    2:服务端又配置了默认为gb2312

    3:Request.QueryString默认又会调用HttpUtility.UrlDecode用系统配置编码去解码接收参数。

    文章补充

    1:系统取默认编码的顺序为:http请求头->globalization配置节点-》默认UTF-8

    2:在Url直接输入中文时,不同浏览器处理方式可能不同如:ie不进行编码直接提交,firefox对url进行gb2312编码后提交。

    3:对于未编码“中文字符”,使用Request.QueryString时内部调用HttpUtility.UrlDecode后,由gb2312->utf-8时,

    如果查不到该中文字符,默认转成
    "%ufffd",因此出现不可逆乱码。

    4:解决之路

    知道了原理,解决的方式也有多种多样了:

    1:全局统一为UTF-8编码,省事又省心。

     

    2:全局指定了GB2312编码时,url带中文,js非编码不可,如ext.js框架。

    这种方式你只能特殊处理,在服务端指定编码解码,
    因为默认系统调用了一次HttpUtility.UrlDecode("xxx",系统配置的编码),
    因此你再调用一次HttpUtility.UrlEncode("xxx",系统配置的编码),返回到原始urt
    -8编码参数
    再用HttpUtility.UrlDecode("xxx",utf-8),
    解码即可。

    5:其它说明:默认对进行一次解码的还包括URI属性,而Request.RawUrl则为原始参数

  • 相关阅读:
    iOS 面试题搜集
    iOS 常用第三方类库、完整APP示例
    iOS 键盘遮挡输入 解决办法
    iOS UIColor RGB HEX
    iOS APP性能优化
    iOS Swift 数组 交换元素的两种方法
    iOS CoreData primitive accessor
    iOS Start developing ios apps (OC) pdf
    iOS 传值方式
    iOS IB_DESIGNABLE IBInspectable @IBDesignable @IBInspectable 加速UI开发
  • 原文地址:https://www.cnblogs.com/zhwl/p/2397590.html
Copyright © 2020-2023  润新知