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

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

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

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5686151.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存