java访问url编码

使用java程序或者服务器后端程序访问某个url时,可以使用java.net.URL类,也可以使用apache的HttpClient包。
为了验证功能,在本地程序中可简单使用URL类,代码如下:
	public static String accessUrl(String urlString) throws IOException {
		URL url = new URL(urlString);
		HttpURLConnection urlcon = (HttpURLConnection) url.openConnection();
		urlcon.connect();
		InputStream is = urlcon.getInputStream();
		BufferedReader buffer = new BufferedReader(new InputStreamReader(is));

		StringBuffer bs = new StringBuffer();
		String l = null;
		while ((l = buffer.readLine()) != null) {
			bs.append(l);
		}
		String result = bs.toString();
		return result;
	}

但是放到tomcat服务器上运行时,却发现读取中文结果出现乱码。比如在调用QQ的api接口获取用户信息时,发现在java程序读取的"北京"和"男",却变成了"鍖椾含"和"鐢?。
尝试用new String(apiResult.getBytes("GBK"),"UTF-8");进行编码转发,发现双字的"北京"可以转换正确,单字的"男"或三字等字符串的最后一个字却不能正确转换。
猜测是使用URL的InputStream和Reader读取字节时使用的字节和本地环境有关:单个程序使用的是java的UTF-8,和服务器返回编码一致,不出现问题;在本地tomcat上运行时可能依赖于操作系统,使用GBK进行解码,导致出现乱码;又因为对服务器UTF8编码字节做GBK解码时导致数据丢失,再怎么编解码转不回来。

解决方案如下:
1.指定Reader的字符集
使用InputStream构建Reader时指定字符集与服务器一致,为UTF-8即可
		BufferedReader buffer = new BufferedReader(new InputStreamReader(is,
				"UTF-8"));

2.使用HttpClient
	public static String accessUrl(String urlString)
			throws ClientProtocolException, IOException {
		HttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(urlString);
		HttpResponse response = httpClient.execute(httpGet);
		String message = EntityUtils.toString(response.getEntity());
		// System.out.println(message);
		return message;
	}

HttpClient会优先使用响应Entity的ContentType的字符集,如果读取不到则使用指定的默认字符集,如果未指定则使用HttpClient的默认字符集(ISO-8859-1),源码如下:
	public static String toString(HttpEntity entity, Charset defaultCharset)
        throws IOException, ParseException
    {
......
        Charset charset = null;
        try
        {
            ContentType contentType = ContentType.get(entity);
            if(contentType != null)
                charset = contentType.getCharset();
        }
        catch(UnsupportedCharsetException ex)
        {
            throw new UnsupportedEncodingException(ex.getMessage());
        }
        if(charset == null)
            charset = defaultCharset;
        if(charset == null)
            charset = HTTP.DEF_CONTENT_CHARSET;
        Reader reader = new InputStreamReader(instream, charset);
......

所以如果服务器返回的响应里面没有ContentType且返回信息有中文,使用HttpClient也需要指定字符集
String message = EntityUtils.toString(response.getEntity(),"UTF-8");

建议使用HttpClient可以用到连接池等特性,https时也不用重复加载证书库。

猜你喜欢

转载自sb33060418.iteye.com/blog/2249619