3

我正在开发一个 Android 应用程序,并且已经发现不同的 Android 版本在处理 Http(s)URLConnections (http://stackoverflow.com/q/9556316/151682) 上有不同的方式。

我遇到了 Android 4 很好地通过 HTTPS 执行 POST 请求的问题,在运行下面的代码时会自动添加诸如 Content-Type 之类的标头。

但是,在 Android 2.3.5(设备和模拟器)上,对输出流的任何写入似乎都被忽略了 - 我使用 Web 代理 Charles 对其进行了调试,并且在发送所有标头时,写入输出流的数据不会一起发送...

任何人都知道如何解决这个问题?

注意:由于我正在开发的 API 只有一个自签名证书,所以此时我需要禁用证书验证。

TIA,帕特里克

更新 与此同时,我也尝试过以下操作,但无济于事:

  • 在 BufferedOutputStream 上调用close()之后调用flush()
  • 同时调用close()OutputStream 和 BufferedOutputStream
  • 改用 OutputStreamWriter
  • 打电话close()前不打电话getInputStream()

    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setConnectTimeout(CONNECT_TIMEOUT);
    
    connection.setDoOutput(true); // Triggers POST.
    connection.setRequestMethod("POST");
    int contentLength = 0;
    if(body != null) {
        contentLength = body.getBytes().length;
    }
    
    // Workarounds for older Android versions who do not do that automatically (2.3.5 for example)
    connection.setRequestProperty(HTTP.TARGET_HOST, url.getHost());
    connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    
    // Set SSL Context -- Development only
    if(context != null && connection instanceof HttpsURLConnection){
        HttpsURLConnection conn = (HttpsURLConnection)connection;
        conn.setSSLSocketFactory(context.getSocketFactory());
        conn.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    }
    
    try{
        // Add headers
        if(headers != null){
            for (NameValuePair nvp : headers) {
                if(nvp != null){
                    connection.setRequestProperty(nvp.getName(), nvp.getValue());
                }
            }
        }
    
        connection.setFixedLengthStreamingMode(contentLength);
        OutputStream outputStream = null;
        try {
            if(body != null){
                outputStream = connection.getOutputStream();
                BufferedOutputStream stream = new BufferedOutputStream(outputStream);
                stream.write(body.getBytes()); // <<<< No effect ?!
                stream.flush();
    
            }
        } finally {
            if (outputStream != null) 
                try { 
                    outputStream.close(); 
                }
            catch (IOException logOrIgnore) {
                // ...
            }
        }
    
        InputStream inputStream = connection.getInputStream();
    
        // .... Normal case ....
    
    }
    catch(IOException e){
        // ... Exception! Check Error stream and the response code ...
    
    
    }
    finally{
        connection.disconnect();
    }
    

    }

4

2 回答 2

6

对我来说,你打电话的顺序等似乎DoSetOutput是奇怪行为的原因......

Android上HTTP POST的一些链接/源代码:

于 2012-04-14T06:58:50.240 回答
4

啊,终于找到了。找错地方了……问题出在标题上:

我上面的代码实际上工作正常 - 原因是我包含了一个 Base64 编码的标头。在我的 Android 2.3.5 上,指定的选项 ( Base64.DEFAULT) 似乎在末尾插入了一个额外的换行符,这会提前结束请求,让我没有时间发送实际的正文。在 Android 4 上,默认值似乎更改为 BASE64.NO_WRAP 之类的内容,如下面链接的帖子中所述...

这其实已经在这里回答了。

感谢您的努力。

于 2012-04-21T18:39:23.380 回答