Mar
20


2008-03-20 3:50 pm 作者:问问题的小孩

基于web的应用开发都会涉及到编码问题,特别是中文编码,一直是开发人员常见问题之一,也最为初学者所困扰。我们知道计算机最初是按英语单字节字符设计的,现在很多软件及系统仍然默认使用ISO8859-1编码来表示。因此,有的时候处理中文字符就会出现乱码的现象。出现乱码不只是简单的由某个软件所造成的,很可能与系统或相关软件有关联影响。  在web软件开发过程中,我们将涉及到四个可能会导致字符编码问题的方面,分别为浏览器、中间件(WEB服务器)、数据库、操作系统。在这四个方面,都有影响字符编码的因素存在。每个方面都有自己默认支持的字符编码,如果这四方面的编码是统一的一种字符集,一定不会出现乱码问题。出问了乱码,一定是其中某部分有不同的字符集编码存在。目前解决此类的问题的方法也是多种多样,本文提到的也是其中的一种,也许别人有更好的方法欢迎大家一起进行探讨。

  操作系统本地编码与你所选择安装的系统版本有关,如果你是简体windows,就是GB编码,如果你是繁体windows,就是BIG5编码。所以我们在不同的操作系统上创建一个源码文件,由于系统的不同就会存储成不同编码格式。这个时候当采用另外一种编码格式的操作系统来读取这个源码文件的时候,内容就会是乱码的。同理,采用浏览器解析的时候也是一样的。如:你的源码文件是在BIG5编码的操作系统下创建的,而浏览器或是WEB服务器(apache等)采用的是GB2312编码的,这个时候所显示的内容也一定是乱码的。知道乱码的原因了,我们就可以有效的解决这个问题。

  要想彻底解决这个问题,就需要我们决定采用统一的编码。对于当前众多的字符集编码,是UNICODE、ISO8859_1 、GBK还是UTF-8。

  UNICODE编码不兼容ISO8859-1编码,而且容易占用更多的空间。因为对于英文字母,UNICODE也需要两个字节来表示,不便于传输和存储。而UTF-8编码兼容ISO8859-1编码,同时也可以用来表示所有语言的字符。UTF-8编码是不定长编码,每一个字符的长度从1-6个字节不等,并且自带简单的校验功能。在UTF-8编码中通常英文字母都是用一个字节表示,而汉字使用三个字节。虽然说UTF-8编码可以使用更少的空间,但只是相对于UNICODE编码来言,如果只是处理汉字,使用GB2312/GBK才是最节省的。WEB应用,网页中会包含大量的英文字符,由于UTF-8编码对ISO8859-1编码兼容,它是一种兼容所有语言的编码方式 ,所以建议采用UTF-8编码为最佳选择。如果决定采用UTF-8编码,做为统一编码。从开发环境到数据库、中间件、系统平台都需要进行统一。

  开发基于WEB的应用,应该了解到所采用的开发语言内部运算中,对字符操作的编码过程。如java语言,在内部将涉及到的所有字符串都会被转化为UTF-8编码来进行运算。

  字符串在被开发语言转化之前,字符串的字符集是什么? 很多开发语言总是根据操作系统的默认编码字符集来决定字符串的初始编码,而且编译或解释系统的输入和输出的都是采取操作系统的默认编码。问题往往就出在输入与输出的地方。而输入与输出部分涉及到WEB服务器、浏览器、数据库等。出现乱码的时候要分析清楚乱码出自哪儿个部分,是输入部分,还是输出部分,确定问题很是困难。下面分别从几个部分来说这个问题。

  

一,开发环境及浏览器部分

  将开发环境的默认字符集设置为UTF-8编码,很多开发工具都可以自定义设置,如Eclipse可以设置全局默认字符集编码也可以在项目属性中设置项目自身采用的字符集编码。

这样在创建源码文件的时候,文件本身就会采用UTF-8编码格式进行存储。

  在WEB开发过程中,各类源代码文件都是文本文件格式的。如最常见的HTML文件,它就是以文本文件格式存储的。这些文件如果是在系统内直接建立的文件,它的编码就是系统的默认编码。如果是在开发工具中创建的文件,一般情况上都是由开发工具的默认编码设置来决定的。而在HTML文件里,还要使用HTML语法,指定了该文件内容所使用的编码(如< meta http-equiv="content-type" content="text/html; charset=UTF-8">)。如果HTML文件内容没有指定编码,则浏览器自动识别文件的编码。如果HTML内容指定了编码,则浏览器使用HTML指定的编码来显示内容。通常情况下,HTML文件指定的charset和HTML文件自身的编码是一致的,但也有不一致的情况,如果不一致,就会导致网页乱码(此处乱码,只和文本文件编码有关,和数据库无关。)使用专门的网页编辑工具(比如Dreamwave),会自动根据网页中的charset值来编码文件。

二,程序文件部分

  页面文件主要包括html文件及脚本文件及其它由开发语言直接输出内容的文件。对于html文件的编码问题,前面讲过了,这里不再重复。开发语言输出的文件,有的是需要进行编码设置的,如jsp开发的时候,需要在jsp文件的头部对字符集进行声明。

如:<%@ page contentType="text/html;charset= utf-8" %>

在Jsp的html代码中,声明UTF-8编码:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

这样只要保证了这个页面内容的编码与文件本身编码一至就会避免与文件相关的乱码。再有乱码就可能是数据在传递过程中编码不同导致的。对于数据传递过程中出现乱码,一般采用对数据时行过滤来处理,数据统一经过某个程序进行编码处理来解决这个问题。
  例如在java的web应用中采用过滤器的方式进行编码处理,将所有来自浏览器的请求(request)转换为UTF-8,因为浏览器发过来的请求包根据浏览器所在的操作系统编码,可能是各种形式编码。网上这方面的源代码很多,下面就是编码过滤器的源代码。需要配置web.xml 激活该Filter。

SetCharacterEncodingFilter源文件

package org.kyle.web.sample;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
public class SetCharacterEncodingFilter implements Filter
...{
    /** *//**
     * The default character encoding to set for requests that pass through
     * this filter.
     */
    protected String encoding = null;
 
    /** *//**
     * The filter configuration object we are associated with. If this value
     * is null, this filter instance is not currently configured.
     */
    protected FilterConfig filterConfig = null;
 
 
    /** *//**
     * Should a character encoding specified by the client be ignored?
     */
    protected boolean ignore = true;
 
    /** *//**
     * Take this filter out of service.
     */
    public void destroy()
    ...{
        this.encoding = null;
        this.filterConfig = null;
    }
 
    /** *//**
     * Select and set (if specified) the character encoding to be used to
     * interpret request parameters for this request.
     *
     * @param request The servlet request we are processing
     * @param result The servlet response we are creating
     * @param chain The filter chain we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
 throws IOException, ServletException
 ...{
 
        // Conditionally select and set the character encoding to be used
        if (ignore || (request.getCharacterEncoding() == null))
        ...{
            String encoding = selectEncoding(request);
            if (encoding != null)
                request.setCharacterEncoding(encoding);
        }
 
 // Pass control on to the next filter
        chain.doFilter(request, response);
    }
 
 
    /** *//**
     * Place this filter into service.
     *
     * @param filterConfig The filter configuration object
     *                   
     *encoding
     * UTF-8
     *
     */
    public void init(FilterConfig filterConfig) throws ServletException
    ...{
        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        if (value == null)
            this.ignore = true;
        else if (value.equalsIgnoreCase("true"))
            this.ignore = true;
        else if (value.equalsIgnoreCase("yes"))
            this.ignore = true;
        else
            this.ignore = false;
    }
 
    /** *//**
     * Select an appropriate character encoding to be used, based on the
     * characteristics of the current request and/or filter initialization
     * parameters. If no character encoding should be set, return
     * null.
     *
 
 
     * The default implementation unconditionally returns the value configured
     * by the encoding initialization parameter for this
     * filter.
     *
     * @param request The servlet request we are processing
     */
    protected String selectEncoding(ServletRequest request)
    ...{
        return (this.encoding);
    }
}
 
 
     * The default implementation unconditionally returns the value configured
     * by the encoding initialization parameter for this
     * filter.
     *
     * @param request The servlet request we are processing
     */
    protected String selectEncoding(ServletRequest request)
    ...{
        return (this.encoding);
    }
}

在web.xml文件中加注册这个过滤器

 <filter>    <filter-name>setCharacterEncodingFilter</filter-name>

    <display-name>setCharacterEncodingFilter</display-name>

    <description>setCharacterEncodingFilter</description>

    <filter-class>org.kyle.web.sample.SetCharacterEncodingFilter</filter-class>

    <init-param>

      <param-name>encoding</param-name>

      <param-value>UTF-8</param-value>

    </init-param>

 </filter>

这样就可以避免数据在传递过程中因编码不同造成乱码问题。

三,中间件(WEB服务器)

设置WEB服务器的默认编码为UTF-8,与文件编码及文件内容声明编码相同,这样保证了WEB服务器在解释文件的时候不出现乱码问题。

如:

Apache服务器可以在它的httpd.conf配置文件中增加AddDefaultCharset utf-8设置。

Weblogic服务器可以在WEB-INF下的web.xml文件中加入以下设置就可以解决这个问题。

 <context-param> <param-name>weblogic.httpd.inputCharset./*</param-name>

 <param-value>utf-8</param-value>

 </context-param>

其它的WEB服务器在其配置文件中都提供设置默认编码的选项,这里不再一一列举。
四,数据库

  经过上面的处理,会发现你的web程序运转起来后,程序已没有了乱码问题。但是在增加记录的时候有的时候也有乱码出现。这是因为你的数据库编码与你通过程序输入的数据编码不同导致的。这需要设置数据库的编码。每种数据库都有直接修改数据库默认编码的配置项。如mysql数据库,可以在它的my.cnf(win:my.ini|unix/linux:my.cnf)配置文件中设置:

[mysql]
default-character-set=utf-8

但是不建议直接修改数据库的这个编码设置。如果修改了数据库的默认编码配置,就破坏了数据库原有的环境,而数据库通常情况下是多人在使用,并不是做为唯一的项目应用。

在我们的程序里可以采用在连接数据库的时候指定编码来解决这个问题。
通过java程序操作数据库的时候,连接数据库的URL可以写成:

useUnicode=true;characterEncoding=utf-8

如连接mysql数据库:
jdbc:mysql://localhost/test?useUnicode=true;characterEncoding=utf-8

通过PHP程序操作数据库的时候,可以先执行mysql_query(“set names xxxx”);其中xxxx是你网页的编码(charset=xxxx),如果网页中charset=utf8,则xxxx=utf8,如果网页中 charset=gb2312,则xxxx=gb2312。

  通过上面几部分的处理,我们可以彻底解决操作系统、开发环境、web服务器、数据库四部分在整个WEB应用中产生乱码的问题。当然很多时候我们没办法将这四部分调整为相同的编码。如你采用的是别人的web服务器,没有权力修改web服务器的默认编码,那么只有在你的程序中对于需要编码的地方进行转换处理,转换成web服务器相同的编码即可。

推荐(0)
收藏

您必须登录 才能进行评论。

得到OpenID
使用OpenID提供商
35OpenID 35OpenID MyOpenID MyOpenID Flickr Flickr
Google Google Yahoo Yahoo! AOL AOL
Blogger Blogger LiveJournal LiveJournal Verisign Verisign
ClaimID ClaimID Technorati Technorati Vidoop Vidoop
OpenID OpenID 帮助
您还没有登录,请登录后继续操作。
提示:您必需打开Cookie才能使用本系统
请输入您的 OpenID OpenID 登录:
例如:http://yourname.openid.35.com
close