java转码及页面乱码原因分析

       近日,一个同事问我,在windows下面用tomcat跑,不乱码,在linux下面用websphere跑乱码,是怎么回事,笼统的回答是windows和linux默认编码不一致造成,感觉没说清楚,没能说清楚,就代表自己还没掌握。好好梳理一下。

       几个基本的知识点:

       1、String其实和char数组等价,保存为2个字节,为unicode编码。存放在string里面的都是2个字节表示一个字符。

       2、编码方式是针对子节流的,文档保存在磁盘,接收的网络数据都是以字节流方式存放。java读取文件,接收网络数据,应该先从new String(byte[],"编码方式")开始转换为String。

       3、String(byte[],“编码方式”)意思为,将字节流以指定的格式解析,转换为unicode,存放在String内存中。

       4、String的getBytes(“编码格式”)意思为将存放在String里面的字符流,按指定的编码格式转换为字节流。

       5、页面提交的编码行为在http://www.ibm.com/developerworks/cn/java/book_global_development/6/有详细的说明。

       服务器对提交参数解析行为,以tomcat5为例。

       源码CoyoteRequest.java ---此为HttpRequest接口实现,就是servlet中调用的getParameter()

    public String getParameter(String name) {

        if (!requestParametersParsed)

            parseRequestParameters();

        return coyoteRequest.getParameters().getParameter(name);

    }

    protected void parseRequestParameters() {

        .......

        String enc = coyoteRequest.getCharacterEncoding(); -----获取浏览器提交的编码格式,也就是页面提交的Charset-Type指定的编码格式。

        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI(); ----tomcat

        if (enc != null) {

            parameters.setEncoding(enc);

            if (useBodyEncodingForURI) {

                parameters.setQueryStringEncoding(enc);

            }

        } else {

            parameters.setEncoding

                (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);

            if (useBodyEncodingForURI) {

                parameters.setQueryStringEncoding

                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);

            }

        }

        //上面说明页面提交有指定编码格式,则按指定的编码格式解析,否则按默认的ISO-8859-1解析。

        ......

        parameters.handleQueryParameters(); ---此方法调用processParameters

        .....

       }

      

      public void processParameters( byte bytes[], int start, int len, 

                                   String enc ) {

            ..............

             try {

                addParam( urlDecode(tmpName, enc), urlDecode(tmpValue, enc) );

            } catch (IOException e) {

                // Exception during character decoding: skip parameter

            }

           ..............

      } 

      private String urlDecode(ByteChunk bc, String enc)

        throws IOException {

        if( urlDec==null ) {

            urlDec=new UDecoder();   

        }

        urlDec.convert(bc);  ------urlDecode对每个byte进行还原。

        String result = null;

        if (enc != null) {

            bc.setEncoding(enc);

            result = bc.toString(); ------调用return new String( buff, start, end-start, enc );

        } else {

        。。。。

     }

     那我们看看不同服务器下面乱码的原因,做个小程序模拟一下不同服务器下面接收页面数据的流程

     String a = "汉字"; ----假设页面为UTF-8编码,可以用System.out.println(System.getProperty(file.encoding)查看一下

try {

              String b1 = URLEncoder.encode(a,"UTF-8"); //浏览器以UTF-8编码向服务器提交,进行一次编码

              //将byte转换为8859-1

              String d = URLDecoder.decode(b1,"ISO-8859-1"); //服务器先进行url解码,按默认的ISO-8859-1编码格式

               String out = new String(d.getBytes("ISO-8859-1"),"UTF-8"); //服务器getParamet()进行一次编码转换,linux上面服务器的编码格式为UTF-8,用locale 可以查看一下

                System.out.println("out----" + out);//这个等于在linux下面的输出

                String out_gbk = new String(d.getBytes("ISO-8859-1"),"GBK"); //windows下面的tomcat默认编码格式为GBK

                System.out.println("out_gbk----" + out_gbk);//此处表示tomcat输出为乱码

           } catch (UnsupportedEncodingException e) {

               // TODO Auto-generated catch block

               e.printStackTrace();

           }     

       由此可以知道服务器编码格式和页面提交的编码格式不同,造成linux和windows下面web服务器显示一个正常,一个乱码。

     

 

你可能感兴趣的:(java)