这是我在通过钉钉的开发者文档获取部门信息的时候所遇到的问题。
错误提示是这个样子,大致的意思就是json字符串格式错误,在将json字符串转化成json对象的时候出现错误。
后来通过钉钉所提供的的url在浏览器上直接进行访问,会显示如下信息:
这是一串json字符串的代码。
后台代码如下:
JSONArray department = new JSONArray();
try {
URL urlGet = new URL(url);
HttpURLConnection http = (HttpURLConnection) urlGet.openConnection();
http.setRequestMethod("GET"); // 必须是get方式请求
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
http.setDoOutput(true);
http.setDoInput(true);
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");// 连接超时30秒
System.setProperty("sun.net.client.defaultReadTimeout", "30000"); // 读取超时30秒
http.connect();
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = toByteArray(is);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson =JSONObject.fromObject(message);
department = demoJson.getJSONArray("department");
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return department;
通过浏览器直接访问得到的字符串与我后台通过httpURLConection方式得到的字符串进行比较发现后台方式得到的字符串缺失了一部分,这就导致json字符串格式不完整,所以报这个错误。
一开始是怀疑HttpURLConection的get方法限制了获得内容的长度,因为在别的地方用post方式获取过内容更多的数据。但是钉钉获取所有部门只提供get方式。
后来在网上查阅了HttpURLConection的使用方式,其中一部分代码让我开始考虑是输入输出流导致的问题:
package com.cn.testproject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpConnectionUrlDemo {
public static void main(String[] args) throws Exception {
//get();
post();
}
public static void get() throws Exception {
String path = "http://www.baidu.com";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
InputStream inStream = conn.getInputStream();
byte[] data = toByteArray(inStream);
String result = new String(data, "UTF-8");
System.out.println(result);
}
public static void post() throws Exception {
String encoding = "UTF-8";
//post的form参数(json兼职对)
String params = "[{\"addTime\":\"2011-09-19 14:23:02\"[],\"iccid\":\"1111\",\"id\":0,\"imei\":\"2222\",\"imsi\":\"3333\",\"phoneType\":\"4444\",\"remark\":\"aaaa\",\"tel\":\"5555\"}]";
String path = "http://www.baidu.com";
byte[] data = params.getBytes(encoding);
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-javascript; charset=" + encoding);
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
conn.setConnectTimeout(5 * 1000);
OutputStream outStream = conn.getOutputStream();
outStream.write(data);
outStream.flush();
outStream.close();
System.out.println(conn.getResponseCode()); // 响应代码 200表示成功
if (conn.getResponseCode() == 200) {
InputStream inStream = conn.getInputStream();
String result = new String(toByteArray(inStream), "UTF-8");
System.out.println(result); // 响应代码 200表示成功
}
}
private static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
return output.toByteArray();
}
}
这里贴出我一开始输入输出流的处理代码:
InputStream is = http.getInputStream();
int size = is.available();
byte[] jsonBytes = new byte[size];
is.read(jsonBytes);
String message = new String(jsonBytes, "UTF-8");
JSONObject demoJson =JSONObject.fromObject(message);
他所使用的的是通过toByteArray(InputStream input)方法对输入流进行处理,每当输入流input中有内容的时候(即返回值不等于-1)就将内容读到byte数组buffer中,再从buffer中将内容写到输出流output中,最终将output转换成数组返回。
刚开始看到这段代码是很懵逼不能理解的,后来通过debug发现,while循环执行了3次,第一次n=1241,第二次n=198,第三次n=-1跳出循环。
这里对于循环执行了3次恨不能理解,但是如果是执行三次的话,我原先的代码出现问题的原因就是显而易见的了。因为我只执行了一次read,所以网页上的数据我只读到1241个字节,后面的198个字节并没有读取。所以会出现这种错误。
这里顺便贴出read()和read(byte[]) 的区别:
1:read() :
从输入流中读取数据的下一个字节,返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回-1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
2:read(byte[] b) :
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。如果 b 的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。将读取的第一个字节存储在元素 b[0] 中,下一个存储在 b[1] 中,依次类推。读取的字节数最多等于 b 的长度。设 k 为实际读取的字节数;这些字节将存储在 b[0] 到 b[k-1] 的元素中,不影响 b[k] 到 b[b.length-1] 的元素。
由帮助文档中的解释可知,read()方法每次只能读取一个字节,所以也只能读取由ASCII码范围内的一些字符。这些字符主要用于显示现代英语和其他西欧语言。而对于汉字等unicode中的字符则不能正常读取。只能以乱码的形式显示。
对于read()方法的上述缺点,在read(byte[] b)中则得到了解决,就拿汉字来举例,一个汉字占有两个字节,则可以把参数数组b定义为大小为2的数组即可正常读取汉字了。当然b也可以定义为更大,比如如果b=new byte[4]的话,则每次可以读取两个汉字字符了,但是需要注意的是,如果此处定义b 的大小为3或7等奇数,则对于全是汉字的一篇文档则不能全部正常读写了。
两者区别转载自: > http://wentao365.iteye.com/blog/1374731