原生Java做HTTP请求会强制断开服务器连接的错误(HttpURLConnection 异常关闭)

2021/4/16 20:27:08

本文主要是介绍原生Java做HTTP请求会强制断开服务器连接的错误(HttpURLConnection 异常关闭),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

今天想写一个Java http请求的工具包,为了方便性的考虑,使用原生Java。结果在写GET的时候就出了问题:

package com.liushx.utils.Http;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HttpRequester {
    private Integer connectTimeout = 30000;
    private Integer readTimeout = 30000;

    /**
     * 获取响应头,并把响应头转换成普通格式
     * @param result 输出的结果
     * @param source 响应头
     */
    public void parseHeader(Map<String, String> result, Map<String, List<String>> source) {
        Set<String> keys = source.keySet();

        for (String k: keys){
            List<String> value = source.get(k);
            result.put(k, value.get(0));
        }
    }

    /**
     * 配置请求头
     * @param header 请求头
     */
    public void setRequestHeader(Map<String, String> header, HttpURLConnection connection) {
        Set<String> keys = header.keySet();
        for (String key: keys){
            connection.setRequestProperty(key, header.get(key));
        }
    }

    public void GET(String url, Map<String, String> headers, HttpResult result){
        int code = 0;
        String text;
        InputStream stream = null;
        BufferedReader reader = null;


        Map<String, String> respHeaders = new HashMap<>();

        try {
            URL apiUrl = new URL(url);

            HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection();
            connection.setRequestMethod("GET");
            // 设置连接超时时间
            connection.setConnectTimeout(connectTimeout);
            // 设置响应超时时间
            connection.setReadTimeout(readTimeout);

            setRequestHeader(headers, connection);
            // 开始请求
            connection.connect();
            code = connection.getResponseCode();
            System.out.print(connection.getResponseMessage());

            if (code == 200){
                stream = connection.getInputStream();
                reader = new BufferedReader(new InputStreamReader(stream));
                StringBuilder stringBuilder = new StringBuilder();
                while ((text = reader.readLine()) != null){
                    stringBuilder.append(text);
                    stringBuilder.append("\n");
                }
                result.setHttpResponseBody(stringBuilder.toString());

                stream.close();
                reader.close();
                connection.disconnect();
            }else{
                result.setErrorMessage(connection.getResponseMessage());
                connection.disconnect();
            }

            Map<String, List<String>> headersMap = connection.getHeaderFields();

            parseHeader(respHeaders, headersMap);
            result.setResponseHeader(respHeaders);
            result.setCode(code);


        } catch (IOException e) {
            try{
                if (stream != null){
                    stream.close();
                }

            }catch (IOException ignored){}
            try{
                if (reader != null){
                    reader.close();
                }

            }catch (IOException ignored){}
        }
    }

    public Integer getReadTimeout() {
        return readTimeout;
    }

    public void setReadTimeout(Integer readTimeout) {
        this.readTimeout = readTimeout;
    }

    public Integer getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(Integer connectTimeout) {
        this.connectTimeout = connectTimeout;
    }
}

 

另外用python的Django写了一个服务端,提供简单的接口用于测试

在Java客户端得到数据,程序退出的时候,Django服务端报了个错误:

ConnectionResetError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。

  

 

 

 

可以看出来是socket异常断开导致的

在网上找了一圈,发现一个大佬的一个说法:

http://cn.voidcc.com/question/p-erxxoacl-by.html

 

 

所以问题明确了,代码红色部分,关闭数据流和连接的顺序不对,如果想缓存socket的话,可以按照红色代码,最后关闭connection,这样会把连接进行缓存,从我这个报错来看,socket会保持连接。

所以在我程序退出的时候,由于连接仍然存活,导致服务端在访问socket的时候出现了连接被强制断开的错误。

正确的关闭顺序应该是这样:

            if (code == 200){
                stream = connection.getInputStream();
                reader = new BufferedReader(new InputStreamReader(stream));
                StringBuilder stringBuilder = new StringBuilder();
                while ((text = reader.readLine()) != null){
                    stringBuilder.append(text);
                    stringBuilder.append("\n");
                }
                result.setHttpResponseBody(stringBuilder.toString());

                // 关闭连接的顺序,如果connection.disconnect()放在stream和reader关闭后调用
                // 那么将不会关闭客户端和服务器的socket连接,如此会导致脚本结束后,连接强制断开
                // 所以,如果不需要缓存socket,那么应该首先断开socket连接
                connection.disconnect();
                stream.close();
                reader.close();
            }else{
                result.setErrorMessage(connection.getResponseMessage());
                connection.disconnect();
            }

疑问解决了。

 



这篇关于原生Java做HTTP请求会强制断开服务器连接的错误(HttpURLConnection 异常关闭)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程