HttpURLConnection 网络连接

Java 中提供了Http 网络请求的API,即HttpURLConnection,在Android 中,许多网络请求框架也是对HttpURLConnection 的封装处理。这里以实例的方式介绍一下HttpURLConnection 的常见用法。

1. GET 请求

GET 请求可以说是http 请求中最常用的了,那么用HttpURLConnection 要怎么实现呢,可见下面代码:

    @NotNull
    public String doGet() {

        try {
            URL requestUrl = new URL(url);                                          // url 是请求地址

            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();         // 创建HttpURLConnection 实例
          
            connection.setConnectTimeout(10000);                                // 设置连接超时时间,单位 ms
            connection.setReadTimeout(15000);                                       // 设置读取返回值的超时时间
          
            connection.setInstanceFollowRedirects(false);               // 不自动跟随重定向

            connection.setRequestProperty("Cookie", cookie);        // 设置cookie,其实就是请求头中的一个字段值
          
            if (headers != null) {                                                          // headers 是一个key 和 value 均为String 的map,下面代码是批量设置请求头的字段值
                headers.forEach(connection::setRequestProperty);
            }

            InputStream inputStream = connection.getInputStream();          // 获取输入流,此时会进行网络连接,并以流的形式返回结果

            connection.disconnect();                                                // 关闭连接

            return readStreamToString(inputStream);                 // readStreamToString 是一个自己写的将流读成字符串的方法
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

因为是GET 请求,所以请求参数可以放在url 中。

2. POST 请求

POST 和 GET 请求的区别这里不再赘述,使用POST 请求和GET 请求有一些不同,如下例

    @NotNull
    public String doPost() {
        try {
            URL requestUrl = new URL(url);

            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();

            connection.setRequestMethod("POST");                                                    // 需要设置请求方法,默认是GET
          
            connection.setDoInput(true);                                                                    // 设置是否从httpUrlConnection读入,默认情况下是true
            connection.setDoOutput(true);                                                                   // POST 要设置为true,默认为false
          
            connection.setUseCaches(false);                                                             // POST 请求不使用缓存
          
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Cookie", cookie);
          
            if (headers != null) {                                                                              // 设置请求头
                headers.forEach(connection::setRequestProperty);
            }

            String paramStr = JSON.toJSONString(params);                                    // params 是一个key 为String,value 为Object 的map,使用框架将其转为json串

            OutputStream os = connection.getOutputStream();                             // 下面这一段代码是通过向HttpURLConnection 写入流的方式设置请求参数
            os.write(paramStr.getBytes());
            os.flush();
            os.close();

            connection.disconnect();

            return readStreamToString(connection.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
3. 上传文件

在post请求传递参数时知道,可以从连接中得到一个输出流,输出流可以向服务器写数据。同理,可以使用这个输出流将文件写到服务器。

    public String uploadFile(String filePath) {
        try {
            URL requestUrl = new URL(url);
            
            HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
            connection.setRequestMethod("POST");
            
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setUseCaches(false);
            
            connection.setRequestProperty("Content-Type", "file/*");                //设置数据类型

            OutputStream outputStream = connection.getOutputStream();
            FileInputStream fileInputStream = new FileInputStream(filePath);        //把文件封装成一个流
            
            int length;
            byte[] bytes = new byte[1024];
            
            while ((length = fileInputStream.read(bytes)) != -1){
                outputStream.write(bytes,0,length);                             //写的具体操作
            }
            
            fileInputStream.close();
            outputStream.close();

            return readStreamToString(connection.getInputStream());

        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

可见,上传文件其实和POST 请求很类似,只是设置请求Header 的 “Content-Type” 有所不同。

注意:

1)HttpURLConnection的connect() 函数,实际上只是建立了一个与服务器的tcp 连接,并没有实际发送http请求。 无论是POST 还是GET,http请求实际上直到HttpURLConnection的getInputStream() 这个函数里面才正式发送出去。

2)在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,对connection对象的一切配置(那一堆set函数)都必须要在connect() 函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。这些顺序实际上是由http请求的格式决定的。如果inputStream读操作在outputStream的写操作之前,会抛出异常: java.net.ProtocolException: Cannot write output after reading input.......

3)http请求实际上由两部分组成,一个是http头,所有关于此次http 请求的配置都在http 头里面定义,一个是正文content。 connect() 函数会根据HttpURLConnection 对象的配置值生成http 头部信息,因此在调用connect 函数之前, 就必须把所有的配置准备好。

4)在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http 正文。至此,http请求的东西已经全部准备就绪。在getInputStream() 函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http 请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream() 函数之后对connection 对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。

你可能感兴趣的:(HttpURLConnection 网络连接)