Android使用HttpUrlConnection进行POST请求时出现“already connected”错误

8

我试图使用HttpUrlConnection进行POST调用,但一直失败。经常出现“IllegalStateException:already connected”错误消息。我不想重复使用连接。请检查我的代码,告诉我是否有任何错误:

public static final int CONNECTION_TIME_OUT = 10000;

public SimpleResponse callPost(String urlTo, Map<String, String> params) {
    System.setProperty("http.keepAlive", "false");
    HttpURLConnection conn = null;
    SimpleResponse response = new SimpleResponse(0, null);
    try {
        URL url = new URL(urlTo);
        conn = (HttpURLConnection) url.openConnection();
        conn.setUseCaches(false);
        conn.setAllowUserInteraction(false);
        conn.setConnectTimeout(CONNECTION_TIME_OUT);
        conn.setReadTimeout(CONNECTION_TIME_OUT);
        conn.setInstanceFollowRedirects(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Connection", "close");
        conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);

        OutputStream os = conn.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
        writer.write(paramsToString(params));
        writer.flush();
        writer.close();
        os.close();

        int responseCode = conn.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream in = conn.getInputStream();
            String result = StringUtils.fromInputStream(in);
            response = new SimpleResponse(responseCode, result);
            in.close();
        } else {
            response = new SimpleResponse(responseCode, null);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (conn != null) {
        conn.disconnect();
    }
    return response;
}

private String paramsToString(Map<String, String> params) {
        if (params == null || params.isEmpty()) {
            return "";
        }
        Uri.Builder builder = new Uri.Builder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            builder.appendQueryParameter(entry.getKey(), entry.getValue());
        }
        return builder.build().getEncodedQuery();
    }

更新:

有时候有效,有时候无效!
有些项目可以用,而有些则不行!
使用完全相同的代码,每次都会出现同样的异常:已连接
为什么我不能每次都获得一个新的连接呢?


当然,活动存在问题,请添加您的代码。 - W4R10CK
@W4R10CK 我只是在 AsyncTask 中进行一次调用。 - Hamzeh Soboh
顺便说一下,那个conn.disconnect()块应该真的放在finally块中。这可能是你出错的原因,因为可能会有其他异常在已连接的消息之前发生,然后所有随后的消息都将失败。 - Laurentiu L.
这个问题一遍又一遍地被问到,最有可能的解释是:https://dev59.com/YV0a5IYBdhLWcg3w07kt#38072310 - Martin Zeitler
你为什么不在输出所有流之后尝试 conn.connect() 呢?如果这样可以的话,我会解释原因。 - Nouman Ghaffar
显示剩余8条评论
3个回答

3
我认为你的问题在于这个:
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));

我看不到 postDataBytes 被声明的地方,但由于您在 paramsToString 中处理参数,我的猜测是它们之间没有关联。
现在,我不是 RFC 2616 (HTTP) 的专家,但我认为发生的情况是 postDataBytes 的长度大于您的请求大小,因此服务器没有断开套接字。这些 URLConnection 对象是池化的,因此当您获取连接对象时,其值已被清理以便重用,但实际连接仍然保持打开状态。
以下是一些代码,我认为您应该尝试。如果它不能解决您的问题,那么我就无法获得声望奖励,但它肯定比您目前的代码更正确:
private static final String CHARSET = "ISO-8859-1";  // or try "UTF-8"

public SimpleResponse callPost(String urlTo, Map<String, String> params) {

// get rid of this...
//    System.setProperty("http.keepAlive", "false");

    HttpURLConnection conn = null;
    SimpleResponse response = new SimpleResponse(0, null);
    try {
        URL url = new URL(urlTo);
        conn = (HttpURLConnection) url.openConnection();
        conn.setUseCaches(false);
        conn.setAllowUserInteraction(false);
        conn.setConnectTimeout(CONNECTION_TIME_OUT);
        conn.setReadTimeout(CONNECTION_TIME_OUT);
        conn.setInstanceFollowRedirects(false);
        conn.setRequestMethod("POST");
// ... and get rid of this
//        conn.setRequestProperty("Connection", "close");
        conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded; charset=" + CHARSET);

        String content = paramsToString(params);
        int length = content.getBytes(Charset.forName(CHARSET)).length;
        conn.setRequestProperty("Content-Length", Integer.toString(length));
        conn.setDoOutput(true);

        OutputStream os = conn.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, CHARSET));
        writer.write(content);
        writer.flush();
        writer.close();
        os.close();

        int responseCode = conn.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream in = conn.getInputStream();
            String result = StringUtils.fromInputStream(in);
            response = new SimpleResponse(responseCode, result);
            in.close();
        } else {
            response = new SimpleResponse(responseCode, null);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (conn != null) {
        conn.disconnect();
    }
    return response;
}

对于任何编译错误,我深表歉意。没有IDE,我的工作毫无用处。我已经尽力校对过了。

我使用了Latin-1编码。如果您不满意,可以尝试UTF-8。

另外一件您可以尝试的事情是彻底放弃内容长度,并调用

        conn.setChunkedStreamingMode(0);

是的,我知道getBytes()调用和OutputStreamWriter正在重复执行相同的过程。在解决这个问题之前,您可以先处理一下这个。


非常感谢您的回答!但是,你能想象到你的代码和我的代码在 conn.setUseCaches 处在第一次请求时就会崩溃吗?我开始相信第三方的请求没有被断开。我将 Firebase 崩溃报告和 Google Analytics 导入到我的项目中,但我不确定这是否是原因。让我认为是这样的原因是,当我创建一个新项目并执行完全相同的代码时,它可以完美地运行! - Hamzeh Soboh
如果您的代码在新项目中能够正常运行,那么您需要逐步将 Firebase 或分析代码添加回去,直到找到导致代码崩溃的更改。某些东西导致打开的连接被返回到连接池中,您需要找出是什么原因。 - kris larson
好的,Kris,你得到了积分,但我没有接受答案,因为对我来说仍然是匿名的,不知道是什么原因导致这个问题,并且为什么会随机发生!谢谢。 - Hamzeh Soboh

2

我不知道为什么会出现“已连接错误”,但这是我用于进行POST请求的代码。发送请求后,我关闭了输入/输出流和连接,这可能有所帮助(虽然我不确定)。

try {
        URL url = new URL(stringURL);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
        connection.setRequestProperty("Accept","application/json");
        //connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
        //connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setReadTimeout(10*1000);
        connection.setUseCaches(false);
        connection.setDoInput(true);
        connection.setDoOutput(true);

        //Request
        DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
        wr.writeBytes(params[1]);
        wr.flush();
        wr.close();

        //Response
        InputStream is = connection.getInputStream();
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
        String line;
        response = new StringBuffer();
        //Expecting answer of type JSON single line {"json_items":[{"status":"OK","message":"<Message>"}]}
        while ((line = rd.readLine()) != null) {
            response.append(line);
        }
        rd.close();
        System.out.println(response.toString()+"\n");
        connection.disconnect(); // close the connection after usage

    } catch (Exception e){
        System.out.println(this.getClass().getSimpleName() + " ERROR - Request failed");
    }

0

网上有一些教程可能会对你有所帮助

  1. Android Httpurlconnection Post 和 Get 请求教程 在这里

  2. 如何使用 HttpURLConnection POST 数据到 Web 服务器?在这里

  3. Android 使用 HttpURLConnection 进行 POST 和 GET 请求教程 在这里


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接