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

原文地址:https://www.cnblogs.com/soul-wonder/p/8892735.html