带有POST数据的Android HttpsUrlConnection无法在Gingerbread上运行

时间:2014-07-20 11:33:18

标签: java android https httpsurlconnection

我已编写代码从外部服务器下载一些数据。服务器使用自签名证书,需要设置会话cookie和一些POST数据。目前我有以下代码:

private byte[] getResponse(URL url, String postData) 
    throws IOException, KeyManagementException, CertificateException, KeyStoreException, 
    NoSuchAlgorithmException
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.setRequestProperty("User-Agent", userAgent);
    urlConnection.setRequestProperty("Cookie", cookie);
    urlConnection.setRequestMethod("POST");
    urlConnection.setDoInput(true);
    urlConnection.setDoOutput(true);

    urlConnection.setSSLSocketFactory(getSocketFactory());

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

    try {
        urlConnection.connect();
        InputStream is = urlConnection.getInputStream();
        int len = 0;
        while ((len = is.read(buffer)) != -1) 
        {
            baos.write(buffer, 0, len);
        }

    }
    catch(IOException e)
    {
        throw e;
    }
    finally {
        urlConnection.disconnect();
    }
    return baos.toByteArray();
}

在冰淇淋三明治及更高级别(API> = 14)一切正常。当我尝试使应用程序在API> = 8上运行时,问题就出现了。现在正在使用GET正确发送请求而没有参数(CAPTCHA)但是当获取实际数据时urlConnection的连接方法失败毫无例外。 getSocketFactory()的代码是:

private SSLSocketFactory getSocketFactory() 
    throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, 
    KeyManagementException
{
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = context.getResources().openRawResource(R.raw.historiapojazdu);
    Certificate ca;
    try {
    ca = cf.generateCertificate(caInput);
    } finally {
    caInput.close();
    }
    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    return context.getSocketFactory();
}

编辑:我刚刚意识到连接方法显然有效,但它没有跟上响应的重定向,因此输入流始终为空。

1 个答案:

答案 0 :(得分:0)

我自己就是这么想的。尽管隐式调用setInstanceFollowRedirects(true),看起来HttpsUrlConnection根本不遵循API 10上的重定向并且由于某种原因而降低。它只是忽略了这个设置。在调用urlConnection.connect()后,我已经使用此代码解决了这个问题:

String redirect = urlConnection.getHeaderField("Location");
        if(redirect != null)    //truth before ICS
        {
            urlConnection.disconnect();

            urlConnection = (HttpsURLConnection) (new URL(redirect)).openConnection();
            urlConnection.setRequestProperty("User-Agent", userAgent);
            urlConnection.setRequestProperty("Cookie", cookie);
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoInput(true);
            urlConnection.setDoOutput(true);

            urlConnection.setSSLSocketFactory(getSocketFactory());

            OutputStream os2 = urlConnection.getOutputStream();
            BufferedWriter writer2 = new BufferedWriter(
                    new OutputStreamWriter(os2, "UTF-8"));
            writer2.write(postData);
            writer2.flush();
            writer2.close();
            os2.close();

            urlConnection.connect();
        }