IE中打开UTF-8编码title为中文的网页会显示空白页的问题

程序生成的静态页面,在内网测试时完全正常,当放到外网后生成的静态页面可以load下代码但不显示页面。郁闷了2天....今天终天在网上找到问题的原因了。原因:因为IO流没有设置编码,内网服务器的编码是GB2312,而外网是则是UTF-8,所以在外网生成的静态页面虽然在http头中标示了GB2312,还是不能显示。解决办法,PrintWriter myFile =new PrintWriter(new OutputStreamWriter(new FileOutputStream(文件名),"gb2312"));

 

以下为转:http://yskin.net/2006/08/ie-utf-8-bug.html

浏览器(无论是IE还是Firefox)在解析页面时,首先取HTTP Header中的Content-Type项,如果有写明charset的话就认定页面的编码方式为charset指定的值。如果没有指明,则认定为默认值。IE中文版的默认值是GB2312,Firefox中文版的默认值是GBK,不过IE的GB2312好像和GBK没啥区别。然后,浏览器会看一下有没有BOM。一旦发现有UTF-8的3字节BOM,则重新认定页面的编码方式为UTF-8。

然后是解码阶段,解码完成后是解析html的阶段。解析html的过程中,当解析到head部分的meta标签时,浏览器会根据<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />这个语句中的说明,重新认定编码方式为charset后面的方式,中断html解析过程,返回到解码步骤重新解码。

知道了这个步骤,再来看这个表:在加了Header语句设置了HTTP Header后,两个浏览器解析所有页面都是用的UTF-8方式,包括GBK编码的页面。(当然要正常解析GBK编码的文件,可以在title前加上个meta标签标明编码方式。)在上表的下半部分可以清楚的看到这一点。再来看上半部分,在没有加Header语句的页面里,首先浏览器认定页面编码方式为默认值GBK。检测有无UTF-8的3字节BOM,检测到的,认定页面编码方式为UTF-8,解码再解析html,一切正常。如上表所示,上半部分带BOM的页面都能正常显示。如果没有BOM,页面可能是GBK或者UTF-8(no BOM)格式,浏览器会先按照默认的GBK方式开始解码。页面为GBK格式时,无meta时正常,有meta时浏览器解析到meta标签会回头重现按UTF-8方式解码,所以GBK,meta在前或后,无论IE还是FF都是乱码。再看UTF-8(no BOM)的页面,无meta时FF用GBK方式解码下去,最终显示乱码,IE则解码出错,形成空白页。有meta时,Firefox找到meta后回头重新按UTF-8方式解码,所以无论meta在前或在后都是正常;IE则是在meta在前时能够和Firefox一样回头重新解码,当meta在后时,又是解析到title出错,返回空白页。

所以,IE显示空白页的问题,很明显是因为IE的解码程序兼容性差。上网查了下,GBK的编码范围是0×8140-0xfefe。从GB2312-80开始,因为ASCII码的范围是0~127,首字位是0,所以GB2312-80使用双字节,并设置首字位为1。“GBK 亦采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间。”UTF-8中中文都是3个字节的,由于Unicode中中日韩的文字都混在一起,可以使用Windows自带的字符映射表查看CJK表意字符的范围,即为汉字的范围。(可以参考我的里的图片)3字节的UTF-8编码是这样子的:1110xxxx 10xxxxxx 10xxxxxx,编码范围是8000-EFFF,首字节在80-EF之间,尾字节在00-FF之间。显然当一段UTF-8编码的文本被按照GBK方式解码的时候,由于有一些编码在GBK中不存在,造成解码程序出现错误。当UTF-8文本被按照GBK的方式解码的时候,前两个字节会被认为是一个字,后一个字节将和下一个字符结合。当<title>标签里的汉字数是偶数个时,勉强有3/4的概率通过解码程序(因为GBK的第二个字节要求是40-FE),当有奇数个汉字的时候,最后一个汉字的三个字节的最后一个字节会和</title>的第一个字符<结合,而<的编码是3C,正好不在尾字节40-FE的范围中,造成错误。如果</title>标签前有多余的空格也会产生错误,因为空格的编码20也不在范围中。

关于BOM

    BOM全称是Browser Object Model,在不依赖于网页内容的情况下提供和浏览器视窗交互的对象,下图显示了BOM的组成结构。

 

可以看出,window是BOM的核心对象,在使用window中所有对象时,可以省去window,例如window.document可以写成document,window.frames[0]可以写成frame[0]。为了对视窗进行操作,BOM提供了四种方法:moveBy(dx,dy)、moveTo(x,y)、resizeBy(dw,dh)、resizeTo(w,h),这四种方法比较简单,具体使用可以参考相关资料。

    BOM中没有特别复杂的概念,但需要注意的是,现在BOM还没有一个统一的标准,各种浏览器对BOM的支持程度也不一,相同的功能也许其对象描述并不相同,即使是BOM结构本身也存在问题,如location既存在于window下的第二级结构中,也存在于window.document下的第三级结构中,但它们的功能描述是相同的。在目前情况下,只有针对用户所使用的浏览器来定制代码,或为不同的浏览器分别进行代码描述。

 

涉及到IO流,问题可能是用unicode为导向的FileWrite写文件。

在Java的IO中,所有的stream(包括Input和Out stream)都包括两种类型:
1.1 以字节为导向的stream
以字节为导向的stream,表示以字节为单位从stream中读取或往stream中写入信息。以字节为导向的stream包括下面几种类型:
1) input stream:
1) ByteArrayInputStream:把内存中的一个缓冲区作为InputStream使用
2) StringBufferInputStream:把一个String对象作为InputStream
3) FileInputStream:把一个文件作为InputStream,实现对文件的读取操作
4) PipedInputStream:实现了pipe的概念,主要在线程中使用
5) SequenceInputStream:把多个InputStream合并为一个InputStream
2) Out stream
1) ByteArrayOutputStream:把信息存入内存中的一个缓冲区中
2) FileOutputStream:把信息存入文件中
3) PipedOutputStream:实现了pipe的概念,主要在线程中使用
4) SequenceOutputStream:把多个OutStream合并为一个OutStream
1.2 以Unicode字符为导向的stream
以Unicode字符为导向的stream,表示以Unicode字符为单位从stream中读取或往stream中写入信息。以Unicode字符为导向的stream包括下面几种类型:
1) Input Stream
1) CharArrayReader:与ByteArrayInputStream对应
2) StringReader:与StringBufferInputStream对应
3) FileReader:与FileInputStream对应
4) PipedReader:与PipedInputStream对应
2) Out Stream
1) CharArrayWrite:与ByteArrayOutputStream对应
2) StringWrite:无与之对应的以字节为导向的stream
3) FileWrite:与FileOutputStream对应
4) PipedWrite:与PipedOutputStream对应
以字符为导向的stream基本上对有与之相对应的以字节为导向的stream。两个对应类实现的功能相同,字是在操作时的导向不同。如CharArrayReader:和ByteArrayInputStream的作用都是把内存中的一个缓冲区作为InputStream使用,所不同的是前者每次从内存中读取一个字节的信息,而后者每次从内存中读取一个字符。

 
阅读更多 登录后自动展开
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页