概述

由来

在Java的世界中,Http客户端之前一直是Apache家的HttpClient占据主导,但是由于此包较为庞大,API又比较难用,因此并不使用很多场景。而新兴的OkHttp、Jodd-http固然好用,但是面对一些场景时,学习成本还是有一些的。很多时候,我们想追求轻量级的Http客户端,并且追求简单易用。而JDK自带的HttpUrlConnection可以满足大部分需求。Hutool针对此类做了一层封装,使Http请求变得无比简单。

介绍

Hutool-http针对JDK的HttpUrlConnection做一层封装,简化了HTTPS请求、文件上传、Cookie记忆等操作,使Http请求变得无比简单。
Hutool-http的核心集中在两个类:

  • HttpRequest
  • HttpResponse

同时针对大部分情境,封装了HttpUtil工具类。

Hutool-http优点

  1. 根据URL自动判断是请求HTTP还是HTTPS,不需要单独写多余的代码。
  2. 表单数据中有File对象时自动转为multipart/form-data表单,不必单做做操作。
  3. 默认情况下Cookie自动记录,比如可以实现模拟登录,即第一次访问登录URL后后续请求就是登录状态。
  4. 自动识别304跳转并二次请求
  5. 自动识别页面编码,即根据header信息或者页面中的相关标签信息自动识别编码,最大可能避免乱码。
  6. 自动识别并解压Gzip格式返回内容

    使用

    最简单的使用莫过于用HttpUtil工具类快速请求某个页面:
    1. //GET请求
    2. String content = HttpUtil.get(url);
    一行代码即可搞定,当然Post请求也很简单:
    1. //POST请求
    2. HashMap<String, Object> paramMap = new HashMap<>();
    3. paramMap.put("city", "北京");
    4. String result1 = HttpUtil.post(url, paramMap);
    Post请求只需使用Map预先制定form表单项即可。

    更多

    根据Hutool的“便捷性与灵活性并存”原则,HttpUtil的存在体现了便捷性,那HttpRequest对象的使用则体现了灵活性,使用此对象可以自定义更多的属性给请求,以适应Http请求中的不同场景(例如自定义header、自定义cookie、自定义代理等等)。相关类的使用请见下几个章节。

    Http客户端工具类-HttpUtil

概述

HttpUtil是应对简单场景下Http请求的工具类封装,此工具封装了HttpRequest对象常用操作,可以保证在一个方法之内完成Http请求。
此模块基于JDK的HttpUrlConnection封装完成,完整支持https、代理和文件上传。

使用

请求普通页面

针对最为常用的GET和POST请求,HttpUtil封装了两个方法,

  • HttpUtil.get
  • HttpUtil.post

这两个方法用于请求普通页面,然后返回页面内容的字符串,同时提供一些重载方法用于指定请求参数(指定参数支持File对象,可实现文件上传,当然仅仅针对POST请求)。
GET请求栗子:

  1. // 最简单的HTTP请求,可以自动通过header等信息判断编码,不区分HTTP和HTTPS
  2. String result1= HttpUtil.get("https://www.baidu.com");
  3. // 当无法识别页面编码的时候,可以自定义请求页面的编码
  4. String result2= HttpUtil.get("https://www.baidu.com", CharsetUtil.CHARSET_UTF_8);
  5. //可以单独传入http参数,这样参数会自动做URL编码,拼接在URL中
  6. HashMap<String, Object> paramMap = new HashMap<>();
  7. paramMap.put("city", "北京");
  8. String result3= HttpUtil.get("https://www.baidu.com", paramMap);

POST请求例子:

  1. HashMap<String, Object> paramMap = new HashMap<>();
  2. paramMap.put("city", "北京");
  3. String result= HttpUtil.post("https://www.baidu.com", paramMap);

文件上传

  1. HashMap<String, Object> paramMap = new HashMap<>();
  2. //文件上传只需将参数中的键指定(默认file),值设为文件对象即可,对于使用者来说,文件上传与普通表单提交并无区别
  3. paramMap.put("file", FileUtil.file("D:\\face.jpg"));
  4. String result= HttpUtil.post("https://www.baidu.com", paramMap);

下载文件

因为Hutool-http机制问题,请求页面返回结果是一次性解析为byte[]的,如果请求URL返回结果太大(比如文件下载),那内存会爆掉,因此针对文件下载HttpUtil单独做了封装。文件下载在面对大文件时采用流的方式读写,内存中只是保留一定量的缓存,然后分块写入硬盘,因此大文件情况下不会对内存有压力。

  1. String fileUrl = "http://mirrors.sohu.com/centos/7.3.1611/isos/x86_64/CentOS-7-x86_64-DVD-1611.iso";
  2. //将文件下载后保存在E盘,返回结果为下载文件大小
  3. long size = HttpUtil.downloadFile(fileUrl, FileUtil.file("e:/"));
  4. System.out.println("Download size: " + size);

当然,如果我们想感知下载进度,还可以使用另一个重载方法回调感知下载进度:

  1. //带进度显示的文件下载
  2. HttpUtil.downloadFile(fileUrl, FileUtil.file("e:/"), new StreamProgress(){
  3. @Override
  4. public void start() {
  5. Console.log("开始下载。。。。");
  6. }
  7. @Override
  8. public void progress(long progressSize) {
  9. Console.log("已下载:{}", FileUtil.readableFileSize(progressSize));
  10. }
  11. @Override
  12. public void finish() {
  13. Console.log("下载完成!");
  14. }
  15. });

StreamProgress接口实现后可以感知下载过程中的各个阶段。
当然,工具类提供了一个更加抽象的方法:HttpUtil.download,此方法会请求URL,将返回内容写入到指定的OutputStream中。使用这个方法,可以更加灵活的将HTTP内容转换写出,以适应更多场景。

更多有用的工具方法

  • HttpUtil.encodeParams 对URL参数做编码,只编码键和值,提供的值可以是url附带参数,但是不能只是url
  • HttpUtil.toParamsHttpUtil.decodeParams 两个方法是将Map参数转为URL参数字符串和将URL参数字符串转为Map对象
  • HttpUtil.urlWithForm是将URL字符串和Map参数拼接为GET请求所用的完整字符串使用
  • HttpUtil.getMimeType 根据文件扩展名快速获取其MimeType(参数也可以是完整文件路径)

    更多请求参数

    如果想设置头信息、超时、代理等信息,请见下一章节《Http客户端-HttpRequest》。

    Http请求-HttpRequest

介绍

本质上,HttpUtil中的get和post工具方法都是HttpRequest对象的封装,因此如果想更加灵活操作Http请求,可以使用HttpRequest。

使用

普通表单

我们以POST请求为例:

  1. //链式构建请求
  2. String result2 = HttpRequest.post(url)
  3. .header(Header.USER_AGENT, "Hutool http")//头信息,多个头信息多次调用此方法即可
  4. .form(paramMap)//表单内容
  5. .timeout(20000)//超时,毫秒
  6. .execute().body();
  7. Console.log(result2);

通过链式构建请求,我们可以很方便的指定Http头信息和表单信息,最后调用execute方法即可执行请求,返回HttpResponse对象。HttpResponse包含了服务器响应的一些信息,包括响应的内容和响应的头信息。通过调用body方法即可获取响应内容。

Restful请求

  1. String json = ...;
  2. String result2 = HttpRequest.post(url)
  3. .body(json)
  4. .execute().body();

其它自定义项

同样,我们通过HttpRequest可以很方便的做以下操作:

  • 指定请求头
  • 自定义Cookie(cookie方法)
  • 指定是否keepAlive(keepAlive方法)
  • 指定表单内容(form方法)
  • 指定请求内容,比如rest请求指定JSON请求体(body方法)
  • 超时设置(timeout方法)
  • 指定代理(setProxy方法)
  • 指定SSL协议(setSSLProtocol)
  • 简单验证(basicAuth方法)

    Http响应-HttpResponse

介绍

HttpResponse是HttpRequest执行execute()方法后返回的一个对象,我们可以通过此对象获取服务端返回的:

  • Http状态码(getStatus方法)
  • 返回内容编码(contentEncoding方法)
  • 是否Gzip内容(isGzip方法)
  • 返回内容(body、bodyBytes、bodyStream方法)
  • 响应头信息(header方法)

    使用

    此对象的使用非常简单,最常用的便是body方法,会返回字符串Http响应内容。如果想获取byte[]则调用bodyBytes即可。

    获取响应状态码

    1. HttpResponse res = HttpRequest.post(url)..execute();
    2. Console.log(res.getStatus());

    获取响应头信息

    1. HttpResponse res = HttpRequest.post(url)..execute();
    2. //预定义的头信息
    3. Console.log(res.header(Header.CONTENT_ENCODING));
    4. //自定义头信息
    5. Console.log(res.header("Content-Disposition"));

    常用Http状态码-HttpStatus

介绍

针对Http响应,Hutool封装了一个类用于保存Http状态码
此类用于保存一些状态码的别名,例如:

  1. /**
  2. * HTTP Status-Code 200: OK.
  3. */
  4. public static final int HTTP_OK = 200;

UA工具类-UserAgentUtil

由来

User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、浏览器及版本、浏览器渲染引擎等。
Hutool在4.2.1之后支持User-Agent的解析。

使用

以桌面浏览器为例,假设你已经获取了用户的UA:

  1. String uaStr = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1";

获取UA信息

我们可以借助UserAgentUtil.parse方法解析:

  1. UserAgent ua = UserAgentUtil.parse(uaStr);
  2. ua.getBrowser().toString();//Chrome
  3. ua.getVersion();//14.0.835.163
  4. ua.getEngine().toString();//Webkit
  5. ua.getEngineVersion();//535.1
  6. ua.getOs().toString();//Windows 7
  7. ua.getPlatform().toString();//Windows

判断终端是否为移动终端

  1. ua.isMobile();

常见问题

Received fatal alert: handshake_failure 错误

HTTP客户端 - 图1
用户错误如图,场景为使用Hutool-http请求https服务器,原因是JDK中的JCE安全机制导致的问题解决方法如下:

  • 方法1:如果你使用的是JDK8,请升级到JDK8的最新版本(例如jdk1.8.0_181)。
  • 方法2:尝试添加以下代码:
    1. System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");