栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

HttpURLConnection 发送请求 以及 接受数据丢失,响应头部Content-Length不存在的问题处理。

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HttpURLConnection 发送请求 以及 接受数据丢失,响应头部Content-Length不存在的问题处理。

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();
    }
}

但是,上面的方法在某次请求中发生了一些问题:

  1. 没有获取到响应的 Content-Length。
  2. 获取到的数据被截断。

在没有获取到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();
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/685603.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号