java中有很多可以用户发送http请求的工具,而我个人喜欢用更底层一点的,所以就选择了这个java自带的http请求工具。
底层的优点就是可以自定义发送的编码,头部等,很随意。
HttpURLConnection 请求代码
下面是我自己写的发送请求的代码,专门用于发送json格式的请求:
private void httpPost(String body, String httpUrl) { try { URL url = new URL(httpUrl); // utl中用的是http:// 那么返回的就是HttpURLConnection HttpURLConnection connection = (HttpURLConnection) url.openConnection(); // 配置 connection.setRequestMethod("POST"); connection.setDoInput(true); connection.setDoOutput(true); connection.setUseCaches(false); connection.setRequestProperty("Content-Type", "application/json"); // 连接 connection.connect(); // 发送请求 connection.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8)); connection.getOutputStream().close(); // 获取响应 int code = connection.getResponseCode(); int size = connection.getHeaderFieldInt("Content-Length", 1024); byte[] bytes = new byte[size]; InputStream inputStream; if (code == 200) inputStream = connection.getInputStream(); else inputStream = connection.getErrorStream(); int o = inputStream.read(bytes); inputStream.close(); // 流关闭后连接自动断开 System.out.println("code = " + code); System.out.println("size = " + o); // 输出结果 System.out.println(new String(bytes, StandardCharsets.UTF_8)); } catch (IOException e) { e.printStackTrace(); } }
但是,上面的方法在某次请求中发生了一些问题:
- 没有获取到响应的 Content-Length。
- 获取到的数据被截断。
在没有获取到Content-Length时,默认会使用1024大小的bytes,但是在read的时候,只读取到了前十几个字符。
完善后的 HttpURLConnection 请求代码经查阅,发现http响应并不是一定会有Content-Length。当响应数据过大或是客户端选择保持链接(请求头部Connection: keep-alive)的时候,服务端的响应就不会带有Content-Length,而会带有响应头部:Transfer-Encoding: chunked,表示body将会分块传输,而read一次只能读取一块数据,所以就会导致接收数据不全的情况。
在分块传输中,最后一块没有数据但有块的结构,表示数据传输完毕。
所以经过修改,就有了如下的请求代码:
这样数据丢失的情况就没有了。
private void httpPost(String body, String httpUrl) { try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setDoInput(true); connection.setDoOutput(true); connection.setUseCaches(false); connection.setRequestProperty("Content-Type", "application/json"); // 请求 connection.connect(); connection.getOutputStream().write(body.getBytes(StandardCharsets.UTF_8)); connection.getOutputStream().close(); // 响应 int code = connection.getResponseCode(); // + 1 是防止因为缓存被用完而进行无用的扩容。 int ct = connection.getHeaderFieldInt("Content-Length", 1023) + 1; bytes = new byte[ct]; InputStream inputStream; if (code == 200) inputStream = connection.getInputStream(); else inputStream = connection.getErrorStream(); int r, s = 0; while (true) { r = inputStream.read(bytes, s, ct - s); if (r == -1) break; else s += r; if (ct == s) { ct *= 2; // 缓存扩容 bytes = Arrays.copyOf(bytes, ct); } } inputStream.close(); System.out.println("code = " + code); System.out.println("size = " + s); System.out.println(new String(bytes, 0, s, StandardCharsets.UTF_8)); } catch (IOException e) { e.printStackTrace(); } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)