• URLconnection


    URLconnection

    开发中最常用的两种网络请求:

      1、标准Java接口(java.NET) —-HttpURLConnection,可以实现简单的基于URL请求、响应功能; 
      2、Apache接口(org.appache.http)—-HttpClient,使用起来更方面更强大。

    本文重点是URLConnection:

    URLConnection继承体系如下

    URLConnection类本身依赖于Socket类实现网络连接。一般认为,URLConnection类提供了比Socket类更易于使用、更高级的网络连接抽象。

    抽象类 URLConnection 是所有类的超类,它代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源。URLConnection 基于Http协议。通常,创建一个到 URL 的连接需要几个步骤:

    openConnection()connect()
    对影响到远程资源连接的参数进行操作。 与资源交互;查询头字段和内容。

    1. 通过在 URL 上调用 openConnection 方法创建连接对象。 
    2. 处理设置参数和一般请求属性。 
    3. 使用 connect 方法建立到远程对象的实际连接。 
    4. 远程对象变为可用。远程对象的头字段和内容变为可访问。

    使用以下方法修改设置参数:

    • setAllowUserInteraction 设置此 URLConnection 的 allowUserInteraction 字段的值
    • setDoInput 将此 URLConnection 的 doInput 字段的值设置为指定的值。
    • setDoOutput 将此 URLConnection 的 doOutput 字段的值设置为指定的值。
    • setIfModifiedSince 将此 URLConnection 的 ifModifiedSince 字段的值设置为指定的值。
    • setUseCaches 将此 URLConnection 的 useCaches 字段的值设置为指定的值
    • setConnectTimeout 设置一个指定的超时值(以毫秒为单位),该值将在打开到此 URLConnection 引用的资源的通信链接时使用。
    • setReadTimeout 将读超时设置为指定的超时值,以毫秒为单位。

    使用 setDefaultAllowUserInteraction 和 setDefaultUseCaches 可设置 AllowUserInteraction 和 UseCaches 参数的默认值。

    使用以下方法修改一般请求属性:

    • setRequestProperty 设置一般请求属性。
    • addRequestProperty 添加由键值对指定的一般请求属性。

    上面每个 set 方法都有一个用于获取参数值或一般请求属性值的对应 get 方法。 
    例如 
    - getDoInput() 
    - getIfModifiedSince()

    在建立到远程对象的连接后,以下方法用于访问头字段和内容:

    • getContent 获取此 URL 连接的内容。
    • getHeaderField 返回指定的头字段的值。
    • getInputStream 返回从此打开的连接读取的输入流。
    • getOutputStream 返回写入到此连接的输出流。

    某些头字段需要经常访问。以下方法:

    • getContentEncoding 返回 content-encoding 头字段的值。
    • getContentLength 返回 content-length 头字段的值。
    • getContentType 返回 content-type 头字段的值。
    • getDate 返回 date 头字段的值。
    • getExpiration 返回 expires 头字段的值。
    • getLastModifed 返回 last-modified 头字段的值。

    URLConnection类的使用

    发送GET请求示例代码

    1.通过在 URL 上调用 openConnection 方法创建连接对象。 
    2.处理设置参数和一般请求属性。 
    3.使用 connect 方法建立到远程对象的实际连接。 
    4.远程对象变为可用。远程对象的头字段和内容变为可访问。
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    import java.util.Map;
    
    public class URLConnectionGet {
    
        public static void main(String[] args) {
            // TODO 自动生成的方法存根
    
            System.out.println(doGet("http://www.baidu.com",""));
    
        }
    
        public static String doGet(String geturl,String params) {
            String realUrl=geturl+"?"+params;
    
            try {
                //1.通过在 URL 上调用 openConnection 方法创建连接对象
                URL url=new URL(realUrl);
                URLConnection conn=url.openConnection();
    
                //2.处理设置参数和一般请求属性
                //2.1设置参数
                //可以根据请求的需要设置参数 
                conn.setUseCaches(false);
                conn.setConnectTimeout(5000); //请求超时时间
    
                //2.2请求属性 
                //设置通用的请求属性 更多的头字段信息可以查阅HTTP协议
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
    
                //3.使用 connect 方法建立到远程对象的实际连接。 
                conn.connect();
    
                //4.远程对象变为可用。远程对象的头字段和内容变为可访问。 
                //4.1获取响应的头字段
                Map<String, List<String>> headers=conn.getHeaderFields();
                System.out.println(headers); //输出头字段
    
                //4.2获取响应正文
                BufferedReader reader = null;
                StringBuffer resultBuffer = new StringBuffer();
                String tempLine = null;
    
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                while ((tempLine = reader.readLine()) != null) {
                    resultBuffer.append(tempLine);
                }
                //System.out.println(resultBuffer);
                reader.close();
                return resultBuffer.toString();
            } catch (MalformedURLException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            finally {
    
            }
            return null;
    
        }
    }
    View Code

    发送POST请求示例代码

    1.通过在 URL 上调用 openConnection 方法创建连接对象。 
    2.处理设置参数和一般请求属性,获取URLconnection实例对应的输出流来发送数据。 
    3.使用 connect 方法建立到远程对象的实际连接。 
    4.远程对象变为可用。远程对象的头字段和内容变为可访问。
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    import java.util.Map;
    
    public class URLConnectionPost {
    
        public static void main(String[] args) {
            // TODO 自动生成的方法存根
    
            System.out.println();
    
        }
    
        public static String doPost(String posturl,String params) {
    
    
            try {
                //1.通过在 URL 上调用 openConnection 方法创建连接对象
                URL url=new URL(posturl);
                URLConnection conn=url.openConnection();
    
                //2.处理设置参数和一般请求属性
                //2.1设置参数
                //可以根据请求的需要设置参数 
                conn.setDoInput (true);  //默认为true 所以不设置也可以
                conn.setDoOutput(true);  //默认为false 发送post请求必须设置setDoOutput(true)
                conn.setUseCaches(false); //是否可以使用缓存 不使用缓存
                conn.setConnectTimeout(5000);//请求超时时间
    
                //2.2请求属性 
                //设置通用的请求属性 消息报头 即设置头字段 更多的头字段信息可以查阅HTTP协议
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
    
                //2.3设置请求正文 即要提交的数据
                PrintWriter pw=new PrintWriter(new OutputStreamWriter(conn.getOutputStream()));
                pw.print(params);
                pw.flush();
                pw.close();
    
                //3.使用 connect 方法建立到远程对象的实际连接。 
                conn.connect();
    
                //4.远程对象变为可用。远程对象的头字段和内容变为可访问。 
                //4.1获取响应的头字段
                Map<String, List<String>> headers=conn.getHeaderFields();
                System.out.println(headers); //输出头字段
    
                //4.2获取响应正文
                BufferedReader reader = null;
                StringBuffer resultBuffer = new StringBuffer();
                String tempLine = null;
    
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                while ((tempLine = reader.readLine()) != null) {
                    resultBuffer.append(tempLine);
                }
                //System.out.println(resultBuffer);
                reader.close();
                return resultBuffer.toString();
            } catch (MalformedURLException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            } catch (IOException e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            }
            finally {
    
            }
            return null;
    
        }
    }
    View Code

    URLConnection类分析

    URL url = new URL("http://www.baidu.com/");
    URLConnection conn = url.openConnection();
    
    1.URL url = new URL("http://www.baidu.com/");
    查看URL的源码
    public URL(String spec) throws MalformedURLException {
    this(null, spec);
    }
    public URL(URL context, String spec) throws MalformedURLException {
    this(context, spec, null);
    }
    public URL(URL context, String spec, URLStreamHandler handler)
    
    查看源码得知最终URL(String spec)会调用URL(URL context, String spec, URLStreamHandler handler)
    此时此时context和handler为null。
    在构造函数URL(URL context, String spec, URLStreamHandler handler)中
    如果handler为空会调用 handler =getURLStreamHandler(protocol)的方法根据protocol协议初始化handler
    handler为URLStreamHandler的子类实例
    
    2.URLConnection conn = url.openConnection();
    
    public URLConnection openConnection() throws java.io.IOException {
        return handler.openConnection(this);
    }
    
    handler.openConnection(this);返回的是URLConnection子类的实例。所以最好把URLConnection转化

    URLConnection总结

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

      2. 在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重, 
        对connection对象的处理设置参数和一般请求属性和写入提交数据都必须要在connect()函数执行之前完成。对outputStream的写提交数据操作,必须要在inputStream的读操作之前。这些顺序实际上是由http请求的格式决定的。

      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(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。

      5. 使用URLConnection与服务器交互
        InputStream getInputStream()
          返回从此打开的连接读取的输入流。
        OutputStream getOutputStream()
          返回写入到此连接的输出流。
        若只是向服务器请求数据,则为HTTP请求方法为GET。
        若需要向服务器提交数据,必须在先调用setDoOutput(true)。当doOutput属性为true时,请求方法将由GET变为POST。

    HttpURLConnection类

    使用以下方法修改设置参数:

    HttpURLConnection继承自URLConnection,相比较URLConnection类多了以下方法。 
    - setRequestMethod 设置 URL 请求的方法, GET POST HEAD OPTIONS PUT DELETE TRACE 以上方法之一是合法的,具体取决于协议的限制。 
    - setFollowRedirects 设置此类是否应该自动执行 HTTP 重定向(响应代码为 3xx 的请求)。

    使用以下方法修改一般请求属性:

    • setRequestProperty 设置一般请求属性。
    • addRequestProperty 添加由键值对指定的一般请求属性。

    在建立到远程对象的连接后,以下方法用于访问头字段和内容:

    HttpURLConnection继承自URLConnection,相比较URLConnection类多了以下方法。 
    - getResponseCode 从 HTTP 响应消息获取状态码。 
    - getResponseMessage 获取与来自服务器的响应代码一起返回的 HTTP 响应消息(如果有)。

    Java中可以使用HttpURLConnection来请求WEB资源。
    HttpURLConnection对象不能直接构造,需要通过URL.openConnection()来获得HttpURLConnection对象,示例代码如下:

    String szUrl = "http://www.ee2ee.com/";
    URL url = new URL(szUrl);
    HttpURLConnection urlCon = (HttpURLConnection)url.openConnection();

    get请求的使用方法

    HttpURLconnection是同步的请求,所以必须放在子线程中。使用示例如下:

    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                String url = "https://www.baidu.com/";
                URL url = new URL(url);
                //得到connection对象。
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                //设置请求方式
                connection.setRequestMethod("GET");
                //连接
                connection.connect();
                //得到响应码
                int responseCode = connection.getResponseCode();
                if(responseCode == HttpURLConnection.HTTP_OK){
                    //得到响应流
                    InputStream inputStream = connection.getInputStream();
                    //将响应流转换成字符串
                    String result = is2String(inputStream);//将流转换为字符串。
                    Log.d("kwwl","result============="+result);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
    View Code

    get请求的使用方法如上。如果需要传递参数,则直接把参数拼接到url后面,其他完全相同,如下:

    String url = "https://www.baidu.com/?userName=zhangsan&password=123456";

    注意点: 
    1,url与参数之间用?隔开。 
    2,键值对中键与值用=连接。 
    3,两个键值对之间用&连接。

    分析: 
    1, 使用connection.setRequestMethod(“GET”);设置请求方式。 
    2, 使用connection.connect();连接网络。请求行,请求头的设置必须放在网络连接前。 
    3, connection.getInputStream()只是得到一个流对象,并不是数据,不过我们可以从流中读出数据,从流中读取数据的操作必须放在子线程。 
    4, connection.getInputStream()得到一个流对象,从这个流对象中只能读取一次数据,第二次读取时将会得到空数据。

    post请求的使用方法

    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                URL url = new URL(getUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("POST");//设置请求方式为POST
                connection.setDoOutput(true);//允许写出
                connection.setDoInput(true);//允许读入
                connection.setUseCaches(false);//不使用缓存
                connection.connect();//连接
                int responseCode = connection.getResponseCode();
                if(responseCode == HttpURLConnection.HTTP_OK){
                    InputStream inputStream = connection.getInputStream();
                    String result = is2String(inputStream);//将流转换为字符串。
                    Log.d("kwwl","result============="+result);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
    View Code

      使用post请求传递键值对参数

    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                URL url = new URL(getUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("POST"); 
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setUseCaches(false);
                connection.connect();
    
                String body = "userName=zhangsan&password=123456";
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
                writer.write(body);
                writer.close();
    
                int responseCode = connection.getResponseCode();
                if(responseCode == HttpURLConnection.HTTP_OK){
                    InputStream inputStream = connection.getInputStream();
                    String result = is2String(inputStream);//将流转换为字符串。
                    Log.d("kwwl","result============="+result);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
    View Code

     分析: 
    1,post方式传递参数的本质是:从连接中得到一个输出流,通过输出流把数据写到服务器。 
    2,数据的拼接采用键值对格式,键与值之间用=连接。每个键值对之间用&连接。

      使用post请求传递json格式参数

    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                URL url = new URL(getUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("POST"); 
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setUseCaches(false);
                connection.setRequestProperty("Content-Type", "application/json;charset=utf-8");//设置参数类型是json格式
                connection.connect();
    
                String body = "{userName:zhangsan,password:123456}";
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
                writer.write(body);
                writer.close();
    
                int responseCode = connection.getResponseCode();
                if(responseCode == HttpURLConnection.HTTP_OK){
                    InputStream inputStream = connection.getInputStream();
                    String result = is2String(inputStream);//将流转换为字符串。
                    Log.d("kwwl","result============="+result);
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
    View Code

    传递json格式的参数与传递键值对参数不同点有两个: 
    1,传递json格式数据时需要在请求头中设置参数类型是json格式。 
    2,body是json格式的字符串。

    设置请求头

    connection.setRequestMethod("POST");
    connection.setRequestProperty("version", "1.2.3");//设置请求头
    connection.setRequestProperty("token", token);//设置请求头
    connection.connect();

    注意: 
    1,请求头必须在connection.connect();代码前设置。 
    2,可以设置多个请求头参数。

    上传文件

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

    try {
        URL url = new URL(getUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setRequestProperty("Content-Type", "file/*");//设置数据类型
        connection.connect();
    
        OutputStream outputStream = connection.getOutputStream();
        FileInputStream fileInputStream = new FileInputStream("file");//把文件封装成一个流
        int length = -1;
        byte[] bytes = new byte[1024];
        while ((length = fileInputStream.read(bytes)) != -1){
            outputStream.write(bytes,0,length);//写的具体操作
        }
        fileInputStream.close();
        outputStream.close();
    
        int responseCode = connection.getResponseCode();
        if(responseCode == HttpURLConnection.HTTP_OK){
            InputStream inputStream = connection.getInputStream();
            String result = is2String(inputStream);//将流转换为字符串。
            Log.d("kwwl","result============="+result);
        }
    
    } catch (Exception e) {
        e.printStackTrace();
    }
    View Code

    注: 
    1,上传文件使用的是post请求方式。 
    2,使用的原理类似于post请求中上传参数。

    下载文件

    try {
         String urlPath = "https://www.baidu.com/";
          URL url = new URL(urlPath);
          HttpURLConnection connection = (HttpURLConnection) url.openConnection();
          connection.setRequestMethod("GET");
          connection.connect();
          int responseCode = connection.getResponseCode();
          if(responseCode == HttpURLConnection.HTTP_OK){
              InputStream inputStream = connection.getInputStream();
              File dir = new File("fileDir");
              if (!dir.exists()){
                  dir.mkdirs();
              }
              File file = new File(dir, "fileName");//根据目录和文件名得到file对象
              FileOutputStream fos = new FileOutputStream(file);
              byte[] buf = new byte[1024*8];
              int len = -1;
              while ((len = inputStream.read(buf)) != -1){
                  fos.write(buf, 0, len);
              }
              fos.flush();
          }
    
      } catch (Exception e) {
          e.printStackTrace();
      }
    View Code

     

     

    传送门:

    HttpUrlConnection使用详解:https://blog.csdn.net/fightingXia/article/details/71775516

    URLConnection类,HttpURLConnection类的使用和总结:https://blog.csdn.net/laiyaxing/article/details/51585755

  • 相关阅读:
    Rasp技术介绍与实现(一)
    青藤云安全细述:三大云安全工具(CASB、CSPM、CWPP)的使用场景
    CWPP产品市场演进
    Global CyberSecurity Landscape
    Scala学习之路 (五)Scala的关键字Lazy
    Scala学习之路 (四)Scala的数组、映射、元组、集合
    Scala学习之路 (三)Scala的基本使用
    Scala学习之路 (二)使用IDEA开发Scala
    Scala学习之路 (一)Scala的安装
    Azkaban学习之路 (三)Azkaban的使用
  • 原文地址:https://www.cnblogs.com/soul-wonder/p/8892735.html
Copyright © 2020-2023  润新知