博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Request 接收参数乱码原理解析
阅读量:6533 次
发布时间:2019-06-24

本文共 4008 字,大约阅读时间需要 13 分钟。

hot3.png

起因:

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

 

实际情景:

05233813_0LiN.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属性的代码:

05233813_0LiN.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:切入 ()方法

05233813_0LiN.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:切入:

05233813_0LiN.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:切入  ( s, urlencoded, encoding)

05233813_0LiN.gif 代码有点长,就折叠起来了
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(
null
string
.Empty);
        }
    }
}

说明:

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

 

3:结论出来了

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

所有的起因为:

1
:js编码方式为urt
-
8
2
:服务端又配置了默认为gb2312
3
:Request.QueryString默认又会调用HttpUtility.UrlDecode用系统配置编码去解码接收参数。

 

文章补充

05233813_0LiN.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则为原始参数

 

 

 

最后做一下链接:

转载于:https://my.oschina.net/secyaher/blog/274381

你可能感兴趣的文章
通过ActionTrail监控AccessKey的使用
查看>>
从 JavaScript 到 TypeScript
查看>>
一个mysql复制中断的案例
查看>>
【最佳实践】OSS开源工具ossutil-大文件断点续传
查看>>
Linux常用的服务器构建
查看>>
深入了解 Weex
查看>>
异构数据库
查看>>
透视校正插值
查看>>
Cobertura代码覆盖率测试
查看>>
【selenium学习笔记一】python + selenium定位页面元素的办法。
查看>>
Linux禁止ping
查看>>
【Matplotlib】 标注一些点
查看>>
[AX]乐观并发控制Optimistic Concurrency Control
查看>>
自定义类加载器
查看>>
MySQL数据库事务各隔离级别加锁情况--Repeatable Read && MVCC(转)
查看>>
C++构造函数例程
查看>>
把某一列值转换为逗号分隔字符串
查看>>
iOS中--NSArray调用方法详解 (李洪强)
查看>>
MySQL在导入的时候遇到的错误
查看>>
LINUX 常用命令整理
查看>>