【问题标题】:Android POST request using HttpUrlConnection getting "already connected"使用 HttpUrlConnection 的 Android POST 请求“已连接”
【发布时间】:2017-02-05 12:07:57
【问题描述】:

我正在尝试使用 HttpUrlConnection 进行 POST 调用,但没有成功。 我经常收到“IllegalStateException:已连接”错误消息。 我对重用连接不感兴趣。请检查我的代码并告诉我是否做错了什么:

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

更新:

有时有效,有时无效!
适用于某些项目,但不适用于其他项目!
完全相同的代码,每次都出现相同的异常:已连接
为什么我每次都无法获得新的连接?

【问题讨论】:

  • 当然,activity有问题,请添加您的代码。
  • @W4R10CK 我只是在 AsyncTask 中进行调用
  • @HamzehSoboh 哪条线路已经连接好?
  • 顺便说一句,conn.disconnect() 块确实应该在 finally 块中完成。这可能是您收到错误的原因,因为可能有一些其他异常会处理已连接的消息,然后所有后续消息都会失败。
  • 这一行之后conn = (HttpURLConnection) url.openConnection();直接conn.connected的值为true,任何像setUseCachessetDoOutput这样的操作都会通过异常。

标签: android post httpurlconnection


【解决方案1】:

我认为你的问题是这样的:

        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 崩溃报告和谷歌分析导入我的项目。但我不确定是不是这个原因。让我这么想的是,当我创建一个新项目并执行完全相同的代码时,它可以完美运行!
  • 如果您的代码在一个新项目中单独运行,那么您需要使用该项目并一次添加您的 firebase 或分析代码,直到您找到导致您的代码的更改碰撞。 某事导致打开的连接返回到您的连接池,您需要找出它是什么。
  • 好的,克里斯,你得到了分数,但我没有接受答案,因为它对我来说仍然是匿名的,是什么导致了这个问题以及为什么这会随机发生!谢谢。
【解决方案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");
    }

【讨论】:

    【解决方案3】:

    网上有一些tuts可能对你有帮助

    1. Android Httpurlconnection 发布和获取请求教程here

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

    3. Android POST 和 GET 请求使用 HttpURLConnection 教程here

    【讨论】:

      猜你喜欢
      • 2013-12-15
      • 1970-01-01
      • 1970-01-01
      • 2016-12-02
      • 2011-07-24
      • 2012-01-01
      • 1970-01-01
      • 2012-02-04
      • 1970-01-01
      相关资源
      最近更新 更多