使用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时也不用重复加载证书库。