HttpsURLConnection中的哪个方法调用实际上发送了HTTP请求?

时间:2014-07-01 22:50:57

标签: java android http url

编辑:现在我已经发现了一些行为,我想知道,为什么不会在我打电话后立即发送请求flush()?还是close()?为什么要等到我致电getResponseCode()


原始问题:

我是java中的HttpsURLConnection类的新手,并查看了doc并发现它不是很有启发性。我在我正在处理的项目上继承了这段代码(我自己没有写过),并想知道它在做什么,以及如何改进它。例如,我无法判断" writeBytes"实际上发送数据或"关闭。"我查看过很多javadoc并发现它们含糊不清,并且在网上的书籍或博客文章中找不到任何有关此主题的好资源。有人可以赐教,或者给我一些好的资源吗?

顺便说一下,这段代码适用于我正在处理的Android SDK库。

注意:我非常了解HTTP请求的理论。我上课了。我知道所有关于URL参数(使用?name = value)和cookie以及RESTful服务以及TCP和IP ......等等。只是努力寻找好的文档,所以我知道如何使用java库。

编辑:将此更改为HttpClient代码,因为事实证明我无法使用Https并仍然可以看到来自echo服务器的请求。它有同样的想法。

import java.io.BufferedInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class HttpClient
{
    public static final String DEBUG_URL = "http://10.20.1.61:8001/api/ad/v5/";
    public static final String MAPPED_KEYWORDS = "get_mapped_keywords/";

    private static byte[] buffer = new byte[1024];

    static NetworkReturn sendHttpPost(String urlString, String postData)
    {
        URL url;
        HttpURLConnection con = null;

        try {
            url = new URL(urlString);
            con = (HttpURLConnection) url.openConnection();

            con.setRequestMethod("POST");
            con.setRequestProperty("Content-length", String.valueOf(postData.length()));
            con.setRequestProperty("Content-Type", "application/json");
            con.setDoOutput(true);

            DataOutputStream output = new DataOutputStream(con.getOutputStream());

            output.writeBytes(postData);
            output.close();

            StringBuilder result = new StringBuilder(), error = new StringBuilder();

            int responseCode = con.getResponseCode();
            if (responseCode >= 200 && responseCode < 300) 
            {
                if (con.getInputStream() != null) 
                {
                    InputStream in = new BufferedInputStream(con.getInputStream());
                    int length;
                    while ((length = in.read(buffer)) != -1) 
                    {
                        result.append(new String(buffer, 0, length));
                    }
                }
            }
            else 
            {
                if (con.getErrorStream() != null) 
                {
                    InputStream in = new BufferedInputStream(con.getErrorStream());
                    int length;
                    while ((length = in.read(buffer)) != -1) 
                    {
                        error.append(new String(buffer, 0, length));
                    }
                }
            }
            return new NetworkReturn(responseCode, result.toString(), error.toString());

        }
        catch (MalformedURLException e) {
            return new NetworkReturn(-1, "", "MalformedURLException: " + e.getLocalizedMessage());
        }
        catch (IOException e) {
            e.printStackTrace();
            return new NetworkReturn(-1, "", "IOEXCEPTION: " + e.getLocalizedMessage());
        }
        finally {
            if (con != null)
                con.disconnect();
        }
    }
}

3 个答案:

答案 0 :(得分:2)

您调用的第一个从服务器获取输入的方法将设置content-length标头并写入输出。这可能是getResponseCode()或getInputStream(),也可能是getErrorStream()。

如果您使用固定长度或分块传输模式,则直接写入。

答案 1 :(得分:1)

  

例如,我无法判断“writeBytes”是否实际发送数据或   “关闭”。

这有点模棱两可,无法提供实施余地。

问题在于是否使用固定长度或分块请求。默认情况下似乎正在使用固定长度请求,尽管规范不需要它。可以通过HttpURLConnection上的方法控制行为。要指定chunked的使用,您可以致电setChunkedStreamingMode。您也可以调用setFixedLengthStreamingMode来定义请求的固定长度。即使在这种情况下,实现/可以/选择尽早开始发送数据,因为总长度是已知的,因此可以在请求头中正确设置。

实际上,调用writeBytes将(通常)导致数据缓冲,直到达到某个阈值。那时缓冲的数据将被实际写入并且过程将重复。当您调用close时,将写入任何缓冲的数据以及表示http请求结束的必要字节。

flush的显式调用通常也会导致写出任何缓冲数据。

答案 2 :(得分:0)

我终于明白了。 &#34; getResponseCode()&#34;方法是打破骆驼背部的稻草(可以这么说)。因为当我评论出来的东西时,就是当我评论它的一部分时,它没有回复&#34;我在使用的echo服务器上的响应(并将收到的请求打印到终端)。

注意:我使用了几乎相同的HttpClient类,否则echo服务器会打印出这样的加密代码:

  

����5D��s����l!���RMav* X?�+gJ.�+�/��32E98�/A5�P         localhost�

当我将此代码作为Java应用程序运行时,服务器没有向终端打印任何内容: (注意注释掉的部分)

static NetworkReturn sendHttpPost(String urlString, String postData)
    {
        URL url;
        HttpURLConnection con = null;

        try {
            url = new URL(urlString);
            con = (HttpURLConnection) url.openConnection();

            con.setRequestMethod("POST");
            con.setRequestProperty("Content-length", String.valueOf(postData.length()));
            con.setRequestProperty("Content-Type", "application/json");
            con.setDoOutput(true);

            DataOutputStream output = new DataOutputStream(con.getOutputStream());
            output.writeBytes(postData);

            output.close();

            //StringBuilder result = new StringBuilder(), error = new StringBuilder();

            //int responseCode = con.getResponseCode();
            /*
            if (responseCode >= 200 && responseCode < 300) 
            {
                if (con.getInputStream() != null) 
                {
                    InputStream in = new BufferedInputStream(con.getInputStream());
                    int length;
                    while ((length = in.read(buffer)) != -1) 
                    {
                        result.append(new String(buffer, 0, length));
                    }
                }
            }
            else 
            {
                if (con.getErrorStream() != null) 
                {
                    InputStream in = new BufferedInputStream(con.getErrorStream());
                    int length;
                    while ((length = in.read(buffer)) != -1) 
                    {
                        error.append(new String(buffer, 0, length));
                    }
                }
            }
            return new NetworkReturn(responseCode, result.toString(), error.toString());
            */
            return new NetworkReturn();

        }
        catch (MalformedURLException e) {
            return new NetworkReturn(-1, "", "MalformedURLException: " + e.getLocalizedMessage());
        }
        catch (IOException e) {
            e.printStackTrace();
            return new NetworkReturn(-1, "", "IOEXCEPTION: " + e.getLocalizedMessage());
        }
        finally {
            if (con != null)
                con.disconnect();
        }
    }

但是,此代码DID使服务器打印到终端:

static NetworkReturn sendHttpPost(String urlString, String postData)
    {
        URL url;
        HttpURLConnection con = null;

        try {
            url = new URL(urlString);
            con = (HttpURLConnection) url.openConnection();

            con.setRequestMethod("POST");
            con.setRequestProperty("Content-length", String.valueOf(postData.length()));
            con.setRequestProperty("Content-Type", "application/json");
            con.setDoOutput(true);

            DataOutputStream output = new DataOutputStream(con.getOutputStream());
            output.writeBytes(postData);

            output.close();

            //StringBuilder result = new StringBuilder(), error = new StringBuilder();

            int responseCode = con.getResponseCode();
            /*
            if (responseCode >= 200 && responseCode < 300) 
            {
                if (con.getInputStream() != null) 
                {
                    InputStream in = new BufferedInputStream(con.getInputStream());
                    int length;
                    while ((length = in.read(buffer)) != -1) 
                    {
                        result.append(new String(buffer, 0, length));
                    }
                }
            }
            else 
            {
                if (con.getErrorStream() != null) 
                {
                    InputStream in = new BufferedInputStream(con.getErrorStream());
                    int length;
                    while ((length = in.read(buffer)) != -1) 
                    {
                        error.append(new String(buffer, 0, length));
                    }
                }
            }
            return new NetworkReturn(responseCode, result.toString(), error.toString());
            */
            return new NetworkReturn();

        }
        catch (MalformedURLException e) {
            return new NetworkReturn(-1, "", "MalformedURLException: " + e.getLocalizedMessage());
        }
        catch (IOException e) {
            e.printStackTrace();
            return new NetworkReturn(-1, "", "IOEXCEPTION: " + e.getLocalizedMessage());
        }
        finally {
            if (con != null)
                con.disconnect();
        }
    }

并且终端输出是这个(回显服务器,所以这是请求必须看起来像的那样):

POST / HTTP/1.1
Content-Type: application/json
User-Agent: Java/1.7.0_60
Host: localhost:3000
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 16

blah blah blah

这是我做的方法调用:

public class Main
{
    public static void main(String[] args)
    {
        NetworkReturn result = HttpClient.sendHttpPost("http://localhost:3000/", "blah blah blah\n\n");
    }
}

修改 我通过向输出流调用flush来尝试Brett的建议(getResponseCode()仍然被注释掉,所以现在我看到flush是否会使它工作):

...

            DataOutputStream output = new DataOutputStream(con.getOutputStream());
            output.writeBytes(postData);
            output.flush(); //<------------here

            output.close();

            //StringBuilder result = new StringBuilder(), error = new StringBuilder();

            //int responseCode = con.getResponseCode();
            /*
            if (responseCode >= 200 && responseCode < 300) 
            {
                if
...

但我的echo服务器没有打印任何东西。这是有道理的,现在我考虑一下,因为&#34; output.close();&#34;可能会调用&#34; flush()&#34;已经。如果flush()工作,那么我的第一个代码片段(带有getResponseCode()注释掉)可能会有效。

编辑:试图查看512千字节的请求正文是否会产生差异并导致请求被发送,但是当getResponseCode()被注释掉时,它无法正常工作。当我取消注释getResponseCode()时,我确认它有效。

我测试大型&#34;文件的新主要方法&#34;,假设char是1个字节,所以它应该超过512千字节:

public class Main
{
    public static void main(String[] args)
    {
        StringBuilder largeString = new StringBuilder();
        for (int i = 0; i < 524288; i++)
        {
            largeString.append('a');
        }
        largeString.append("\n\n");
        NetworkReturn result = HttpClient.sendHttpPost("http://localhost:3000/", largeString.toString());

    }
}