`
maosuhan
  • 浏览: 109603 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

在做google map api时遇到的字符串编码的各种纠结

    博客分类:
  • java
阅读更多

我们的架构是b/s的,后台用的是tomcat,和google的webservice打交道还用到一个gae做代理。

之前的博文我们说过在tomcat和浏览器之间的ajax交互时要用一种客户端encode两次加上一个辅助函数加工然后服务端decode两次的恶心解决方案。后来我们研究了一下tomcat,发现其实问题是这样的。

 

tomcat默认使用iso-8859-1来解释request的,所以我们用ff提交参数时用的是utf8,我们在浏览器里输入“大学”,其实是被ff encode过的(被转成%B5%33形式),传到服务器时tomcat又用iso-8859-1 decode了。所以我们想到解决方案如下

	String keyword =URLEncoder.encode(request.getParameter("keyword"),"ISO-8859-1");
		keyword=URLDecoder.decode(keyword, "UTF-8");

 这样子我们反过来弄一下就ok了。

这里还要说一下,如果换成时ie的话,默认“大学”这个url参数会用gbk,如果还是用上面的那个,其实就会出现乱码。这里还要说glassfish貌似也是用的iso-8859-1

 

这里还要讲一个关于HTTPURLConnection的事情,我们在tomcat用HTTPURLConnection时,我在设置parameter的时候没有encode我的参数,我就这样传过去了,而在本地的jetty服务器的gae上接收到了我的字符串竟然是对的,看来HttpURLConnection会自动帮我们按照默认的charset(linux下是utf8)把字符串编码再传过去。然后再我们本地的gae上,可以直接写这样的code

     String keyword = req.getParameter("keyword");
        String center = req.getParameter("center");
        String range = req.getParameter("range");

 这个可能gae用的jetty服务器又自动帮我们decode了,这里虽然我们没有decode和encode,但是程序都自动帮我们完成了。但是必须满足客户端和服务器用的默认的编码是一样的。

 

这里讲一下什么是decode什么是encode,比如,我们对一个“作者”encode,这里会encode成     %E4%BD%9C%E8%80%85这样的,再encode一下会,encode成“%25E4%25BD%259C%25E8%2580%2585”这样,%会转成%25。   而decode呢?如果我们对“%25E4%25BD%259C%25E8%2580%2585” decode会变成“%E4%BD%9C%E8%80%85”,而对“%25E4%25BD%259C%25E8%2580%2585大学” decode会变成“%E4%BD%9C%E8%80%85大学”,也就是说decode可能只会对%开头的东西进行decode。而encode比较诡异,处理%的手段让人搞不懂。

 

话说回来,我做了几次实验,我发现URLConnection会自动帮助我们进行编码的,而且很智能,如果我们事先encode过,他就不会再帮我们encode。而本地gae会用默认的utf8方式编码。设想一个情况,我们用gbk encode参数然后再传到gae上,我们就需要在gae上先encode("UTF-8")在decode 成gbk。这里的道理是一样的。而我们可以用一个函数就是request.setCharsetEncoding("GBK")来直接来让服务器帮我们用GBK转,这样就不要先encode再decode了。

 

现在我们看age里面的代码,我们需要请求google的web service。这时,我们仍然是需要用HTTPURLConnection这个类,但是我们在没有encode参数的时候,发给google api时竟然说url是不合法的,一定要实现encode才可以。这就不懂了,为什么一定要我们手动encode呢,不是HTTPURLConnection自动帮我们encode了吗?我想这是不是同一个版本的URLCOnnection啊?我看了一下原来不加encode的错误堆栈信息,原来最后会调用一个什么httpclient的类,而这个类不是标准库里的,是外部的,也不知道这里面到底出了什么鬼!!!就连我step into进去HTTPURLConnection,里面的堆栈也是不一样的,诡异啊!!!

 

接着我们从webservice里获得了json字符串,里面也还是没有decode过的utf8,随即

String allString=URLDecoder.decode(all.toString(),"UTF-8");

 最后还要返回给tomcat结果,此时如果我们不用以下这个字符编码限定会出问题

        resp.setContentType("text/json");
        resp.setCharacterEncoding("UTF-8");
        PrintWriter writer=resp.getWriter();

 我不知道这个是为什么!我看本地的age上默认是utf8啊,难道传过来的时候就不是utf8?

后来我又搞成这样子,在本地gae上这样写

		OutputStream writer = resp.getOutputStream();
		writer.write(jsonString.getBytes());
		writer.close();

 在tomcat上这样写

		byte[] bytes=new byte[10000];
		InputStream inputStream=connection.getInputStream();
		inputStream.read(bytes);
		String string=new String(bytes);

 这样我们用纯字节进行传递就不可能会有错了!!!这里我没有指定到底用什么编码传递,这个时候会用默认的,我始linux的,所以java的默认编码用utf8。

 

 

我们把age部署到服务器,在服务器上出现了诡异,原来服务器上用的是一个us什么的默认编码格式。真正的age要想正常返回给我们字符串,需要加上这么一句话

	BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
				StringBuilder all = new StringBuilder();
				String line = null;
				while ((line = reader.readLine()) != null) {
					all.append(line);
				}
				
 

 在我本地gae是不需要加第一句话中的UTF-8的。因为在服务器上的gae是us编码的,所以需要这么转,否则默认就转成us这种东西了。

这里就又有一个问题了,service传过来的是一个需要decode的东西,我在本地的gae上用

new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));

得到的字符串是需要再一次decode的,而在服务器上的gae是不需要再一次被decode的。

 

终其所述,无论本地还是服务器的age下的HTTPURLConnection和普通java的不一样,它不会帮我们encode;而服务器上gae的InputStreamReader和本地的gae和普通java也不一样,他会自动转码。

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics