各种乱码问题及原理,很全面

切换到十六进制方式,才能清楚地看到,“春节”被转成了“B4 BA BD DA”。

我们知道,“春”和“节”的GB2312编码(我的操作系统“Windows XP”中文版的默认编码)分别是“B4 BA”和“BD DA”。因此,IE实际上就是将查询字符串,以GB2312编码的格式发送出去。

Firefox的处理方法,略有不同。它发送的HTTP Head是“wd=%B4%BA%BD%DA”。也就是说,同样采用GB2312编码,但是在每个字节前加上了%。

所以,结论2就是,查询字符串的编码,用的是操作系统的默认编码。(我使用谷歌浏览器,他会是使用utf-8编码的)

四、情况3:Get方法生成的URL包含汉字

前面说的是直接输入网址的情况,但是更常见的情况是,在已打开的网页上,直接用Get或Post方法发出HTTP请求。

根据台湾中兴大学吕瑞麟老师的试验,这时的编码方法由网页的编码决定,也就是由HTML源码中字符集的设定决定。

如果上面这一行最后的charset是UTF-8,则URL就以UTF-8编码;如果是GB2312,URL就以GB2312编码。

举例来说,百度是GB2312编码,Google是UTF-8编码。因此,从它们的搜索框中搜索同一个词“春节”,生成的查询字符串是不一样的。

百度生成的是%B4%BA%BD%DA,这是GB2312编码。

Google生成的是%E6%98%A5%E8%8A%82,这是UTF-8编码。

所以,结论3就是,GET和POST方法的编码,用的是网页的编码。

参考文献:

五、网页、js编码

五、情况4:Ajax调用的URL包含汉字

前面三种情况都是由浏览器发出HTTP请求,最后一种情况则是由Javascript生成HTTP请求,也就是Ajax调用。还是根据吕瑞麟老师的文章,在这种情况下,IE和Firefox的处理方式完全不一样。

举例来说,有这样两行代码:

url = url + "?q=" +document.myform.elements[0].value; //假定用户在表单中提交的值是“春节”这两个字

http_request.open('GET', url, true);

那么,无论网页使用什么字符集,IE传送给服务器的总是“q=%B4%BA%BD%DA”,而Firefox传送给服务器的总是“q=%E6%98%A5%E8%8A%82”。也就是说,在Ajax调用中,IE总是采用GB2312编码(操作系统的默认编码),而Firefox总是采用utf-8编码。这就是我们的结论4。

六、Javascript函数:escape()

好了,到此为止,四种情况都说完了。

假定前面你都看懂了,那么此时你应该会感到很头痛。因为,实在太混乱了。不同的操作系统、不同的浏览器、不同的网页字符集,将导致完全不同的编码结果。如果程序员要把每一种结果都考虑进去,是不是太恐怖了?有没有办法,能够保证客户端只用一种编码方法向服务器发出请求?

回答是有的,就是使用Javascript先对URL编码,然后再向服务器提交,不要给浏览器插手的机会。因为Javascript的输出总是一致的,所以就保证了服务器得到的数据是格式统一的。

Javascript语言用于编码的函数,一共有三个,最古老的一个就是escape()。虽然这个函数现在已经不提倡使用了,但是由于历史原因,很多地方还在使用它,所以有必要先从它讲起。

实际上,escape()不能直接用于URL编码,它的真正作用是返回一个字符的Unicode编码值。比如“春节”的返回结果是%u6625%u8282,也就是说在Unicode字符集中,“春”是第6625个(十六进制)字符,“节”是第8282个(十六进制)字符。

它的具体规则是,除了ASCII字母、数字、标点符号“@ * _ + - . /”以外,对其他所有字符进行编码。在\u0000到\u00ff之间的符号被转成%xx的形式,其余符号被转成%uxxxx的形式。对应的解码函数是unescape()。

所以,“Hello World”的escape()编码就是“Hello%20World”。因为空格的Unicode值是20(十六进制)。

还有两个地方需要注意。

首先,无论网页的原始编码是什么,一旦被Javascript编码,就都变为unicode字符。也就是说,Javascipt函数的输入和输出,默认都是Unicode字符。这一点对下面两个函数也适用。

其次,escape()不对“+”编码。但是我们知道,网页在提交表单的时候,如果有空格,则会被转化为+字符。服务器处理数据的时候,会把+号处理成空格。所以,使用的时候要小心。

七、Javascript函数:encodeURI()

encodeURI()是Javascript中真正用来对URL编码的函数。

它着眼于对整个URL进行编码,因此除了常见的符号以外,对其他一些在网址中有特殊含义的符号“; / ? : @ & = + $ , #”,也不进行编码。编码后,它输出符号的utf-8形式,并且在每个字节前加上%。

它对应的解码函数是decodeURI()。

需要注意的是,它不对单引号'编码。

八、Javascript函数:encodeURIComponent()

最后一个Javascript编码函数是encodeURIComponent()。与encodeURI()的区别是,它用于对URL的组成部分进行个别编码,而不用于对整个URL进行编码。

因此,“; / ? : @ & = + $ , #”,这些在encodeURI()中不被编码的符号,在encodeURIComponent()中统统会被编码。至于具体的编码方法,两者是一样。

它对应的解码函数是decodeURIComponent()。

参考文献:

六、tomcat容器的编码 1、启动tomcat容器时的编码

在第二节中,说道:慎用getBytes(),他是基于平台的,tomcat中JVM启动的时候file.encoding这个属性值到底是什么,由谁决定?

Linux修改catalina.sh文件

JAVA_OPTS=”-server-Dfile.encoding=GBK-Xms=512m-Xmx1024m-XX:PermSize=128m-XX:MaxPermSize=256m-verbose:gc-Xloggc:${CATALINA_HOME}/logs/gc.log`date+%Y-%m-%d-%H-%M`-XX:+UseConcMarkSweepGC-XX:+CMSIncrementalMode-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-noclassgc”

如果你像上面这样告诉JVM,启动我tomcat容器的时候,使用GBK来编码,后续的getBytes返回的就是GBK编码的东西,这点特别在部署的tomcat的时候注意。

2、tomcat对表单中get提交的数据,出乱码看哪里?

get提交的tomcat从4.x之后不是使用request.setCharacterEncoding("字符集"),从这里获取,它直接使用直接对参数进行编码,这个编码他是从tomcat的配置文件中获取

3、tomcat对表单中post提交的数据,出乱码看哪里?

对于post需要在web.xml里面配置拦截器,主要是在程序第一次从request里面获取参数之前把request给设定了具体的编码

publicvoiddoFilter(ServletRequest req, ServletResponse resp,FilterChain chain)throwsIOException, ServletException {

req.setCharacterEncoding(encoding);//这里是过滤器,直接设置编码

HttpServletRequest request = (HttpServletRequest)req;

HttpServletResponse response = (HttpServletResponse)resp;

ActionContext.setContext(request, response);

chain.doFilter(req,resp);

ActionContext.removeContext();

还有一点需要注意的是:你在web.xml里面配置过滤器的优先级是不是最高,一定要在request出现之前拦截。

4、tomcat对jsp页面的编码,看哪里?

你还记得jsp页面中有下面这句话么?pageEncoding="utf-8"告诉tomcat,你编译我jsp文件的时候使用他来编译,如果这句话没有,他默认使用charset=utf-8"这句话来编译,同时注意保存jsp的时候使用编码也应该与pageEncoding="utf-8"保持一致

你还记得下面这句话么?由他来告诉浏览器使用什么编码的

七、mysql数据库的编码 1、查看数据库编码

需要以root用户身份登陆才可以查看数据库编码方式(以root用户身份登陆的命令为:

>mysql-u root –p,之后两次输入root用户的密码),查看数据库的编码方式命令为:

>show variables like 'character%';

+--------------------------+----------------------------+

| Variable_name | Value |

+--------------------------+----------------------------+

| character_set_client | latin1 |

| character_set_connection | latin1 |

| character_set_database | latin1 |

| character_set_filesystem | binary |

| character_set_results | latin1 |

| character_set_server | latin1 |

| character_set_system | utf8 |

| character_sets_dir | /usr/share/mysql/charsets/ |

+--------------------------+----------------------------+

从以上信息可知数据库的编码为latin1,需要修改为gbk或者是utf8;

其中,character_set_client为客户端编码方式;character_set_connection为建立连接使用的编码;character_set_database数据库的编码;

character_set_results结果集的编码;

character_set_server数据库服务器的编码;

只要保证以上四个采用的编码方式一样,就不会出现乱码问题。

2、更改数据库编码

停止MySQL的运行

/etc/init.d/mysql start (stop)为启动和停止服务器

MySQL主配置文件为my.cnf,一般目录为/etc/mysql

var/lib/mysql/放置的是数据库表文件夹,这里的mysql相当于windows下mysql的date文件夹

当我们需要修改MySQL数据库的默认编码时,需要编辑my.cnf文件进行编码修改,在linux下修改mysql的配置文件my.cnf,文件位置默认/etc/my.cnf文件

找到客户端配置[client]在下面添加

default-character-set=utf8默认字符集为utf8

在找到[mysqld]添加

default-character-set=utf8默认字符集为utf8

init_connect='SET NAMES utf8'(设定连接mysql数据库时使用utf8编码,以让mysql数据库为utf8运行)

3、改了之后,为什么win里面cmd中的那个console控制台还是显示乱码了?

Mysql通过客户端发送到控制台展示之前是utf8,但是console是使用系统的默认编码(gbk),所以在中文的时候发生了乱码显示,但是不影响程序操作,只是显示的时候有问题。

如何解决了?

方法一:(只对当前窗口有用,推荐使用)

输入:set names gbk

方法二:将控制台展示编码改成utf8(对所有的窗口,不推荐)

1、打开CMD.exe命令行窗口

2、通过chcp命令改变代码页,UTF-8的代码页为65001

F:\trash>chcp 65001

执行该操作后,代码页就被变成UTF-8了。但是,在窗口中仍旧不能正确显示UTF-8字符。

3、修改窗口属性,改变字体

在命令行标题栏上点击右键,选择"属性"->"字体",将字体修改为True Type字体"Lucida Console",然后点击确定将属性应用到当前窗口。

4、通过以上操作并不能完全解决问题,因为显示出来的内容有可能不完全。可以先最小化,然后最大化命令行窗口,文件的内容就完整的显示出来了。

Java开发中,常常会遇到乱码的问题,一旦遇到这种问题,常常就很扯蛋,每个人都不愿意承认是自己的代码有问题。其实编码问题并没有那么神秘,那么不可捉摸,搞清Java的编码本质过程就真相大白了。

先看个图:

其实,编码问题存在两个方面:JVM之内和JVM之外。

1、Java文件编译后形成class

这里Java文件的编码可能有多种多样,但Java编译器会自动将这些编码按照Java文件的编码格式正确读取后产生class文件,这里的class文件编码是Unicode编码(具体说是UTF-16编码)。

因此,在Java代码中定义一个字符串:

String s="汉字";

不管在编译前java文件使用何种编码,在编译后成class后,他们都是一样的----Unicode编码表示。

2、JVM中的编码

JVM加载class文件读取时候使用Unicode编码方式正确读取class文件,那么原来定义的String s="汉字";在内存中的表现形式是Unicode编码。

当调用String.getBytes()的时候,其实已经为乱码买下了祸根。因为此方法使用平台默认的字符集来获取字符串对应的字节数组。在WindowsXP中文版中,使用的默认编码是GBK,不信运行下:

publicclassTest {

publicstaticvoidmain(String[] args) {

System.out.println("当前JRE:"+ System.getProperty("java.version"));

System.out.println("当前JVM的默认字符集:"+ Charset.defaultCharset());

当前JRE:1.6.0_16

当前JVM的默认字符集:GBK

当不同的系统、数据库经过多次编码后,如果对其中的原理不理解,就容易导致乱码。因此,在一个系统中,有必要对字符串的编码做一个统一,这个统一模糊点说,就是对外统一。比如方法字符串参数,IO流,在中文系统中,可以统一使用GBK、GB13080、UTF-8、UTF-16等等都可以,只是要选择有些更大字符集,以保证任何可能用到的字符都可以正常显示,避免乱码的问题。(假设对所有的文件都用ASCII码)那么就无法实现双向转换了。

要特别注意的是,UTF-8并非能容纳了所有的中文字符集编码,因此,在特殊情况下,UTF-8转GB18030可能会出现乱码,然而一群傻B常常在做中文系统喜欢用UTF-8编码而不说不出个所以然出来!最傻B的是,一个系统多个人做,源代码文件有的人用GBK编码,有人用UTF-8,还有人用GB18030。FK,都是中国人,也不是外包项目,用什么UTF-8啊,神经!源代码统统都用GBK18030就OK了,免得ANT脚本编译时候提示不可认的字符编码。

因此,对于中文系统来说,最好选择GBK或GB18030编码(其实GBK是GB18030的子集),以便最大限度的避免乱码现象。

3、内存中字符串的编码

内存中的字符串不仅仅局限于从class代码中直接加载而来的字符串,还有一些字符串是从文本文件中读取的,还有的是通过数据库读取的,还有可能是从字节数组构建的,然而他们基本上都不是Unicode编码的,原因很简单,存储优化。

因此就需要处理各种各样的编码问题,在处理之前,必须明确“源”的编码,然后用指定的编码方式正确读取到内存中。如果是一个方法的参数,实际上必须明确该字符串参数的编码,因为这个参数可能是另外一个日文系统传递过来的。当明确了字符串编码时候,就可以按照要求正确处理字符串,以避免乱码。

在对字符串进行解码编码的时候,应该调用下面的方法:

getBytes(String charsetName)

String(byte[] bytes, String charsetName)

而不要使用那些不带字符集名称的方法签名,通过上面两个方法,可以对内存中的字符进行重新编码。

更多“CSS中,通过链接伪类可以实现不同的链接状态,下列说法错误的是:”相关的问题

更多“CSS中,通过链接伪类可以实现不同的链接状态,下列说法错误的是:”相关的问题

第1题

【单选题】CSS中,通过链接伪类可以实现不同的链接状态。下列用来定义未访问时超链接状态的是:

A.a:link

B.a:visited

C.a:hover

D.a:active

点击查看答案

第2题

有关伪类的说法不正确的是()

A.并不是真正意义上的类,它的名称是由系统定义的

B.通常由标记名、类名或 id 名加“:”构成

C.在 CSS 中,通过链接伪类可以实现不同的链接状态

D.伪类就是以 # 定义的超链接

点击查看答案

第3题

有关伪类的说法不正确的是()

A.并不是真正意义上的类,它的名称是由系统定义的

B.通常由标记名、类名或 id 名加“:”构成

C.在 CSS 中,通过链接伪类可以实现不同的链接状态

D.伪类就是以 定义的超链接

点击查看答案

第4题

【单选题】CSS中,通过链接伪类可以实现不同的链接状态,下列说法错误的是()

A.a:link{ CSS样式规则; }超链访问时的状态

B.a:visited{ CSS样式规则; } 访问后超链接的状态

C.a:hover{ CSS样式规则; }鼠标经过、悬停时超链接的状态

D.a: active{ CSS样式规则; }鼠标点击不动时超链接的状态

点击查看答案

第5题

CSS中,通过链接伪类可以实现不同的链接状态,下列说法错误的是()

A.link{ CSS样式规则; } 超链访问时的状态

B.visited{ CSS样式规则; } 访问后超链接的状态

C.hover{ CSS样式规则; } 鼠标经过、悬停时超链接的状态

D.active{ CSS样式规则; } 鼠标点击不动时超链接的状态

点击查看答案

第6题

什么是css链接伪类?

点击查看答案

第7题

【判断题】链接伪类可以实现不同的链接状态,a:active用来定义鼠标点击后超链接的状态

点击查看答案

第8题

下面哪一种CSS的“高级”样式用于在用户选择链接时重定义链接的显示方式?()

A.伪元素选择器

B. 组合选择器

C. 伪类选择器

D. ID选择器

点击查看答案

第9题

下面哪一种CSS的“高级”样式用于在用户选择链接时重定义链接的显示方式()

A.伪元素选择器

B.组合选择器

C.伪类选择器

D.ID选择器

点击查看答案

第10题

通常网站导航链接应避免:()

A.以CSS实现下拉菜单

B. 链接以Flash实现

C. 链接通过JavaScript调用

D. 链接中带有SessionID以实现对用户行为的跟踪

点击查看答案

本站内容来自用户投稿,如果侵犯了您的权利,请与我们联系删除。联系邮箱:835971066@qq.com

本文链接:http://news.xiuzhanwang.com/post/597.html

发表评论

评论列表

还没有评论,快来说点什么吧~

友情链接: