使用HttpUrlConnection获取"已连接"的Android POST请求

Ham*_*boh 8 post android httpurlconnection

我正在尝试使用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();
    }
Run Code Online (Sandbox Code Playgroud)

更新:

有时工作,有时不工作!
在一些项目上工作,在其他项目上没有!
相同的代码,每次都有相同的异常:已经连接
为什么我每次都无法获得新的连接?

kri*_*son 3

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

        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
Run Code Online (Sandbox Code Playgroud)

我看不到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;
}
Run Code Online (Sandbox Code Playgroud)

对于任何编译错误,我深表歉意。没有IDE我就没啥用。我尽我所能证明了这一点。

我使用Latin-1 编码。如果这不适合您,您可以尝试 UTF-8。

您可以尝试的另一件事是完全放弃内容长度并调用

        conn.setChunkedStreamingMode(0);
Run Code Online (Sandbox Code Playgroud)

是的,我意识到getBytes()调用 和OutputStreamWriter正在重复相同的过程。一旦解决了这个问题,您就可以解决这个问题。