Java实现简单的HTTP远程调用

介绍了一些JDK提供的原生的用于发起HTTP调用的API,比如UTL、HttpURLConnection。

HTTP 协议可能是现在 Internet 上使用得最多、最重要的协议了,越来越多的 Java 应用程序需要直接通过 HTTP 协议,进行HTTP调用来访问网络资源。实际上,上一篇文章学习的的Socket编程对于大多数程序员来说在工作中根本接触不到,接触到最多的就是HTTP远程调用。

HTTP协议位于传输层TCP协议之上的应用层,虽然HTTP协议依赖于TCP,但是肯定不需要再直接使用Socket编程了,当然Java.net包中也为我们提供了可以发起HTTP请求的相关工具类,比如URL、HttpURLConnection。

1 URL

public final class URL
extends Object
implements Serializable

为了更好地面向对象,java将URL封装到了对象之中,该对象就叫URL对象,该对象的类就叫URL类,它表示统一资源定位符。实际上还有一个URI的类,它表示统一资源描述符!

构造器:

URL(String spec) 根据 String 表示形式创建 URL 对象。

API方法,以http://192.168.2.218:8080/myweb/demo.html?username=lisi&age=21演示:

String getProtocol()获取此 URL 的协议名称。http
String getHost()获取此 URL 的主机名称(IP地址)。192.168.2.218
int getPort()获取此 URL 的端口号。如果未设置端口号,则返回-1。8080
String getPath()获取此 URL 的路径部分。如果没有路径,则返回一个空字符串。/myweb/demo.html
String getQuery()获取此 URL 的查询,如果没有查询,则返回 null(传递的参数)。username=lisi&age=21
String toString()获取此 URL 的字符串表示形式。传入的字符串
URLConnection openConnection()和服务器建立连接。返回一个 URLConnection 对象,它表示到URL引用的远程对象(服务器)的连接。
就是把客户端(URL)和服务器(应用程序)的连接也封装到了URLConnection对象之中,能拿到该对象,说明客户端(URL)已经和服务器(应用程序)建立了连接。
InputStream openStream()打开连接,并且返回从此打开的连接读取的输入流。等价于openConnection().getInputStream()

1.1 URLConnection

public abstract class URLConnection
extends Object

抽象类 URLConnection代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源,因此该类实例又叫连接对象。

通过在 URL 上调用 openConnection()方法可以获取连接对象。

API方法:

OutputStream getOutputStream()返回写入到此连接的输出流。可以向服务器(应用程序)发送信息。
InputStream getInputStream()返回从此打开的连接读取的输入流。读取服务器(应用程序)的响应信息。

1.2 使用URL发起请求

使用URL发起网络请求,可以直接从 URL 中读取服务器响应的字节流数据。

这里,我们请求百度的网址!

public class URLTest {
    public static void main(String[] args) throws IOException {
        //创建一个连接到百度的URL
        URL url = new URL("http://www.baidu.com");
        /* 字节流 */
        //InputStream is = url.openConnection().getInputStream();
        InputStream is = url.openStream();
        /* 字符流 */
        InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
        /* 提供缓存功能 */
        BufferedReader br = new BufferedReader(isr);
        String line;
        //每次读取一行的数据输出,实际上输出的是一个HTML页面,也就是说服务器响应的是一个静态HTML页面的代码
        //该页面进过浏览器渲染,我们就能看到熟悉的“百度一下”的界面
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }
}

实际上输出的是一个HTML页面,也就是说服务器响应的是一个静态HTML页面的代码,该页面进过浏览器渲染,我们就能看到熟悉的“百度一下”的界面。

在这里插入图片描述

2 HttpURLConnection

URLConnection支持各种协议的连接,而java.net.HttpURLConnection则表示一个支持HTTP协议和特定功能的URLConnection。使用HttpURLConnection可以比较方便的指定HTTP请求所需要的各种请求头参数,以及获取响应头、响应体等内容。

HttpURLConnection不需要设置socket,HttpURLConnection并不是底层的连接,而是在底层Socket连接上的一个请求。实际底层的Socket网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的InputStream或OutputStream的close()方法以释放请求的网络资源,不过这种方式对于持久化连接没用。对于持久化连接,得用disconnect()方法关闭底层连接的socket。

这个类的使用遵循以下模式:

  1. 通过调用URL.openConnection()来获得一个新的URLConnection对象,并且将其结果强制转换为HttpURLConnection.
  2. 准备请求。一个请求主要的参数是它的URI。请求头可能也包含元数据,例如证书,首选数据类型和会话Cookies.
  3. 可以选择性的上传一个请求体。如果是POST请求,那么HttpURLConnection实例必须设置setDoOutput(true)。如果它包含一个请求体,那么通过将数据写入一个由getOutStream()返回的输出流来传输请求体数据。
  4. 读取响应。响应头通常包含元数据例如响应体的内容类型和长度,修改日期和会话Cookie s。响应体可以被由getInputStream返回的输入流读取。如果响应没有响应体,则该方法会返回一个空的流。
  5. 关闭连接。一旦一个响应体已经被阅读后,HttpURLConnection 对象应该通过调用disconnect()关闭。断开连接会释放被一个connection占有的资源,这样它们就能被关闭或再次使用。

对当当网搜索商品的URL发起GET请求:

public class HttpURLConnectionTest {
    public static void main(String[] args) throws IOException {
        /*
         * 创建一个连接到当当网搜索页面的URL
         */
        String param = "圣诞节";
        URL url = new URL("http://search.dangdang.com/?key=" + param + "&act=input");
        //强制转换为HttpURLConnection
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        /*设置连接参数*/
        //设置连接主机超时(单位:毫秒),即用于connect()方法打开连接时的超时时间
        urlConnection.setConnectTimeout(3000);
        //设置从主机读取数据超时(单位:毫秒),也就是InputStream.read()方法,即从输入流读取数据的超时时间
        urlConnection.setReadTimeout(3000);
        //设置请求方法类型,默认就是GET
        urlConnection.setRequestMethod("GET");
        /*设置请求头的信息*/
        //添加/替换请求头的信息
        urlConnection.setRequestProperty("Content-type", "text/html; charset=gb2312");
        //添加请求头的信息
        //urlConnection.addRequestProperty("Content-type", "text/html;charset=gb2312");
        urlConnection.setRequestProperty("Accept", "*/*");
        urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36");
        urlConnection.setRequestProperty("Connection", "keep-alive");
        /*
         * 连接并发送HTTP请求
         */
        urlConnection.connect();

        /*
         * 获取响应码,判断是否200
         */
        if (urlConnection.getResponseCode() != 200) {
            throw new RuntimeException("bad response");
        }
        /*
         * 获取所有响应头的信息
         */
        Map<String, List<String>> map = urlConnection.getHeaderFields();
        for (String key : map.keySet()) {
            System.out.println(key + ": " + map.get(key));
        }
        /*
         * 获取响应体,获取的是输入流,需要自己转换
         */
        InputStream input = urlConnection.getInputStream();
        /* 字符流 */
        InputStreamReader isr = new InputStreamReader(input, "gb2312");
        BufferedReader br = new BufferedReader(isr);
        String line;
        //输出响应体
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
        br.close();
    }
}

部分响应结果如下:

在这里插入图片描述

对于post请求,需要调用connection.setDoOutput(true)方法,表示设置允许写入,调用connection.setUseCaches(false)方法,表示不使用缓存,并且需要通过connection.getOutputStream()获取输出流,然后将请求体的数据写入到这个输出流中,比较麻烦。

上面的代码仍然非常的繁琐,并且需要手动的处理输入、输出流,所以用起来很麻烦。也就是说,虽然在 JDK 的 java net包中已经提供了访问 HTTP 协议的基本功能,但是对于大部分应用程序来说,JDK库本身提供的功能还不够丰富和灵活。

本次我们仅仅介绍了一些JDK提供的原生的用于发起HTTP调用的API,在实际开发中,我们应该使用更加成熟的被封装好的工具类,比如Apache Common 提供的HttpClient,在Spring项目中,我们可以使用Spring提供的的RestTemplate,并且自 5.0 起,Spring提供了一个非阻塞(异步调用)、响应式的org.springframe.web.reactive.client.WebClient,WebClient同时对同步和异步以及流式的HTTP调用处理方案提供高效支持,用于替代RestTemplate,RestTemplate将在将来的版本中弃用。这些工具类,我们后面做项目的时候自然会遇到!

如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值