Request 接收参数乱码原理解析

简介:

起因:

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

 

实际情景:

复制代码
ExpandedBlockStart.gif
同事负责的平台是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属性的代码:

复制代码
ExpandedBlockStart.gif
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()方法

复制代码
ExpandedBlockStart.gif
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,  true this .QueryStringEncoding);
        
    }
}

复制代码

 

2.3:切入:QueryStringEncoding

复制代码
ExpandedBlockStart.gif
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)

代码有点长,就折叠起来了

说明:

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

 

3:结论出来了

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

所有的起因为:

1 :js编码方式为urt - 8

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

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

 

文章补充

复制代码
ExpandedBlockStart.gif
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则为原始参数

 

 

 

最后做一下链接:路过秋天版博客 V2.0 测试版发布 公测一周

版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:

http://www.cnblogs.com/cyq1162/archive/2010/11/29/1891124.html

相关文章
|
24天前
|
机器学习/深度学习 算法 编译器
【C++ 泛型编程 中级篇】深度解析C++:类型模板参数与非类型模板参数
【C++ 泛型编程 中级篇】深度解析C++:类型模板参数与非类型模板参数
46 0
|
28天前
|
关系型数据库 MySQL Shell
CMake构建Makefile深度解析:从底层原理到复杂项目(三)
CMake构建Makefile深度解析:从底层原理到复杂项目
30 0
|
28天前
|
编译器 vr&ar C++
CMake构建Makefile深度解析:从底层原理到复杂项目(二)
CMake构建Makefile深度解析:从底层原理到复杂项目
33 0
|
24天前
|
存储 安全 编译器
【C++ 17 新功能 std::visit 】深入解析 C++17 中的 std::visit:从原理到实践
【C++ 17 新功能 std::visit 】深入解析 C++17 中的 std::visit:从原理到实践
69 0
|
20天前
|
安全 Java 数据安全/隐私保护
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
【深入浅出Spring原理及实战】「EL表达式开发系列」深入解析SpringEL表达式理论详解与实际应用
43 1
|
23天前
|
存储 并行计算 算法
C++动态规划的全面解析:从原理到实践
C++动态规划的全面解析:从原理到实践
89 0
|
23天前
|
监控 算法 Unix
【Linux 异步操作】深入理解 Linux 异步通知机制:原理、应用与实例解析
【Linux 异步操作】深入理解 Linux 异步通知机制:原理、应用与实例解析
55 0
|
28天前
|
存储 Linux API
解析音频输出调节音量的原理以及调节的方法
解析音频输出调节音量的原理以及调节的方法
33 0
|
28天前
|
安全 JavaScript 前端开发
若依实现单点登录(解析请求链接中的参数做鉴权认证)
若依实现单点登录(解析请求链接中的参数做鉴权认证)
17 0
|
28天前
|
Unix 编译器 Shell
CMake构建Makefile深度解析:从底层原理到复杂项目(一)
CMake构建Makefile深度解析:从底层原理到复杂项目
65 0

推荐镜像

更多