irpas技术客

JAVA http请求工具类_月半花开_http请求工具类

未知 2992

????????日常工作难免遇到调用其他项目接口,一般都是restful风格,这个并非强制风格,根据项目不同能使用的工具不同,主要受限于项目类型:maven项目,一般项目等。有原生http协议进行交互,java原生自带对http的支持并不好用,或者是httpclient,我们不得不重复造轮子。下边就介绍几种通用常用好用的方法。

1. 第一种http-requst

http-request

最大的特点是基于URLConnection实现,不依赖HttpClien

maven引入 <dependency> <groupId>com.github.kevinsawicki</groupId> <artifactId>http-request</artifactId> <version>5.6</version> </dependency> Get请求请求示例 public static HttpRequest get(final URL url) throws HttpRequestException { return new HttpRequest(url, METHOD_GET); }

Get请求获取响应报文

String response = HttpRequest.get("http://·").body(); System.out.println("Response was: "+response);

Get请求,获取响应码

int code = HttpRequest.get("http://google.com").code();

Get请求加请求参数:可以直接加在get方法里,选择是否进行编码,也可以用Map传参

-第一种写法 HttpRequest request = HttpRequest.get("http://google.com", true, 'macId', "10051", "size", "测试机构"); -第二种 写法2: Map data = new HashMap(); data.put("macId", "10051"); data.put("macName", "测试机构"); String result =HttpRequest.get("http://google.com")form(data).body(); System.out.println("result:" + resp); post请求请求示例

发一个带文件的POST请求

HttpRequest request = HttpRequest.post("url”); request.header("Content-Type", "multipart/form-data;boundary=AaB03x"); request.part("imagefile", "test.log", "image/jpeg", new File("d:/test/test.jpg"));

发一个带Form的POST

Map<String, String> data = new HashMap<String, String>(); data.put("user", "A User");\ data.put("state", "CA");\ HttpRequest request = HttpRequest.post(url).form(data);

发送带JSON的POST

JsonObject jsonContent = new JsonObject(); jsonContent.addProperty("content",msgBody); JsonObject jsonData = new JsonObject(); jsonData.add("data",jsonContent); jsonData.addProperty("subtype",subType); HttpRequest httpRequest = HttpRequest.post(url).acceptJson(); httpRequest.send(jsonData.toString()); int code = httpRequest.code(); String body = httpRequest.body();

发送请求上传附件

HttpRequest request=HttpRequest.post("http://google.com"); request.part("status[body]","Making a multipart request"); request.part("status[image]",newFile("/home/kevin/Pictures/ide.png")); if(request.ok()){ System.out.println("Status was updated"); }

常用http请求配置

HttpRequest request = HttpRequest.get("https://google.com"); //信任所有证书 request.trustAllCerts(); //信任所有地址 request.trustAllHosts(); //设置请求超时时间 request.connectTimeout(60000); //设置读取超时时间 request.readTimeout(60000); 以上设置支持Builder模式 String resp = HttpRequest.post("http://·").trustAllCerts().trustAllHosts() .form(data) .connectTimeout(60000) .readTimeout(60000) .body();复制代码

配置http代理

HttpRequest request = HttpRequest.get("https://google.com"); //Configure proxy request.useProxy("localhost", 8080); //Optional proxy basic authentication request.proxyBasic("username", "p4ssw0rd"); ?2.hutool

????????Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的

maven引入

<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version> </dependency>

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

HttpUtil.getHttpUtil.post

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

GET请求例子:

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

POST请求例子:

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

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

String fileUrl = "http://mirrors.sohu.com/centos/8.4.2105/isos/x86_64/CentOS-8.4.2105-x86_64-dvd1.iso"; //将文件下载后保存在E盘,返回结果为下载文件大小 long size = HttpUtil.downloadFile(fileUrl, FileUtil.file("e:/")); System.out.println("Download size: " + size);Copy to clipboardErrorCopied

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

//带进度显示的文件下载 HttpUtil.downloadFile(fileUrl, FileUtil.file("e:/"), new StreamProgress(){ @Override public void start() { Console.log("开始下载。。。。"); } @Override public void progress(long progressSize) { Console.log("已下载:{}", FileUtil.readableFileSize(progressSize)); } @Override public void finish() { Console.log("下载完成!"); } });

StreamProgress接口实现后可以感知下载过程中的各个阶段

Http请求-HttpRequest

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

普通表单

我们以POST请求为例:

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

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

Restful请求Restful请求 String json = ...; String result2 = HttpRequest.post(url) .body(json) .execute().body(); 配置代理

如果代理无需账号密码,可以直接:

String result2 = HttpRequest.post(url) .setHttpProxy("127.0.0.1", 9080) .body(json) .execute().body();

如果需要自定其他类型代理或更多的项目,可以:

String result2 = HttpRequest.post(url) .setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)) .body(json) .execute().body();

如果遇到https代理错误Proxy returns "HTTP/1.0 407 Proxy Authentication Required",可以尝试:

System.setProperty("jdk.http.auth.tunneling.disabledSchemes", ""); Authenticator.setDefault( new Authenticator() { @Override public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(authUser, authPassword.toCharArray()); } } ); 其它自定义项

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

指定请求头自定义Cookie(cookie方法)指定是否keepAlive(keepAlive方法)指定表单内容(form方法)指定请求内容,比如rest请求指定JSON请求体(body方法)超时设置(timeout方法)指定代理(setProxy方法)指定SSL协议(setSSLProtocol)简单验证(basicAuth方法) 第三种:?SpringBoot发送Http请求-RestTemplate

????????RestTemplate是Spring用于同步client端的核心类,简化了与http服务的通信,并满足RestFul原则,程序代码可以给它提供URL,并提取结果。默认情况下,RestTemplate默认依赖jdk的HTTP连接工具。当然你也可以 通过setRequestFactory属性切换到不同的HTTP源,比如Apache HttpComponents、Netty和OkHttp。

? ? ? ?在org.springframework.web中已经默认集成了RestTemplate

pom配置

<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency>

请求示例:

详细代码可以看看这位大佬的:

SpringBoot发送Http请求-RestTemplate_只有变秃,才能更强-CSDN博客_springboot发送http请求

import com.clover.api.utils.tools.ToolUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import java.util.HashMap; import java.util.Map; /** * @author 孤 * @version v1.0 * @Developers 张耀烽 * @serviceProvider 四叶草安全(SeClover) * @description 请简易描述定义 * @date 2020/5/14 */ @Component public class RestMock<k, v> { @Autowired private RestTemplate restTemplate; /** * 生成post请求的JSON请求参数 * 请求示例: * { * "id":1, * "name":"张耀烽" * } * * @return */ public HttpEntity<Map<String, String>> generatePostJson(Map<String, String> jsonMap) { //如果需要其它的请求头信息、都可以在这里追加 HttpHeaders httpHeaders = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8"); httpHeaders.setContentType(type); HttpEntity<Map<String, String>> httpEntity = new HttpEntity<>(jsonMap, httpHeaders); return httpEntity; } /** * 生成get参数请求url * 示例:https://0.0.0.0:80/api?u=u&o=o * 示例:https://0.0.0.0:80/api * * @param protocol 请求协议 示例: http 或者 https * @param uri 请求的uri 示例: 0.0.0.0:80 * @param params 请求参数 * @return */ public String generateRequestParameters(String protocol, String uri, Map<String, String> params) { StringBuilder sb = new StringBuilder(protocol).append("://").append(uri); if (ToolUtil.isNotEmpty(params)) { sb.append("?"); for (Map.Entry map : params.entrySet()) { sb.append(map.getKey()) .append("=") .append(map.getValue()) .append("&"); } uri = sb.substring(0, sb.length() - 1); return uri; } return sb.toString(); } /** * get请求、请求参数为?拼接形式的 * <p> * 最终请求的URI如下: * <p> * http://127.0.0.1:80/?name=张耀烽&sex=男 * * @return */ public String sendGet() { Map<String, String> uriMap = new HashMap<>(6); uriMap.put("name", "张耀烽"); uriMap.put("sex", "男"); ResponseEntity responseEntity = restTemplate.getForEntity ( generateRequestParameters("http", "127.0.0.1:80", uriMap), String.class ); return (String) responseEntity.getBody(); } /** * post请求、请求参数为json * * @return */ public String sendPost() { String uri = "http://127.0.0.1:80"; Map<String, String> jsonMap = new HashMap<>(6); jsonMap.put("name", "张耀烽"); jsonMap.put("sex", "男"); ResponseEntity<String> apiResponse = restTemplate.postForEntity ( uri, generatePostJson(jsonMap), String.class ); return apiResponse.getBody(); } }

第四种:自己定义封装

很多时间受限于项目,开发环境,还是必须自己封装http,下边就这几贴代码了

package com.util.http; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang.StringUtils; /** * RequestHttp概要说明:Http请求工具类 * * @author lcy */ public class RequestHttp { /** * 向指定URL发送GET方法的请求 * * @param url 发送请求的URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return URL 所代表远程资源的响应结果 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建立实际的连接 connection.connect(); // 获取所有响应头字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8")); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输入流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 向指定 URL 发送POST方法的请求 * * @param url 发送请求的 URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打开和URL之间的连接 URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送 POST 请求出现异常!" + e); e.printStackTrace(); } // 使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } /** * asUrlParams方法慨述: 将map转化key=123&v=456格式 为只要确保你的编码输入是正确的,就可以忽略掉 * UnsupportedEncodingException 创 建 人:dyt 创建时间:2022年1月14日 上午10:13:42 修 改 人:dyt * 修改日期:2022年1月14日 上午10:13:42 @param source @return String @throws */ public static String asUrlParams(Map<String, String> source) { Iterator<String> it = source.keySet().iterator(); StringBuilder paramStr = new StringBuilder(); while (it.hasNext()) { String key = it.next(); String value = source.get(key); if (StringUtils.isBlank(value)) { continue; } try { // URL 编码 value = URLEncoder.encode(value, "utf-8"); } catch (UnsupportedEncodingException e) { // do nothing } paramStr.append("&").append(key).append("=").append(value); } // 去掉第一个& return paramStr.substring(1); } /** * 将Object对象里面的属性和值转化成Map对象 * * @param obj * @return * @throws IllegalAccessException */ public static Map<String, Object> convertToMap(Object obj) { try { if (obj instanceof Map) { return (Map) obj; } Map<String, Object> returnMap = BeanUtils.describe(obj); returnMap.remove("class"); return returnMap; } catch (IllegalAccessException e1) { e1.getMessage(); } catch (InvocationTargetException e2) { e2.getMessage(); } catch (NoSuchMethodException e3) { e3.getMessage(); } return new HashMap(); } public static void main(String[] args) { // //发送 GET 请求 // String s=HttpRequest.sendGet("http://localhost:6144/Home/RequestString", "key=123&v=456"); // System.out.println(s); // 发送 POST 请求 String sr = RequestHttp.sendPost("http://localhost:8083/ticket/update_diff", "macId=8001&ticketType=456"); System.out.println(sr); } } 知识点补充 什么是 RESTful

用 URL 定位资源,用 HTTP 动词(GET,POST,DELETE,PUT)描述操作。

RESTful 是一种 web 服务设计风格,风格意思就是大家默认的但不是强制的

?例如:

https://api.example.com/users

这个 URL 一看就知道是对 user 资源的操作。URL 中只使用名词来指定资源,不包含操作。为什么呢?

如果要包含操作,那至少有增删改查四种,那么上例中的一个接口至少要变成四个:

https://api.example.com/add_user https://api.example.com/delete_user https://api.example.com/update_use https://api.example.com/get_user ?用 HTTP 动词描述操作

那怎么描述操作呢?答案就是用 HTTP 动词。

HTTP 动词,可能很多人第一眼看到的时候有点蒙,不知道是啥,其实就是我们请求网页时用的 GET、POST 等操作。我们平时用的最多的就是 GET 和 POST(例如写爬虫的时候,基本都是这两种),常用的还有 PUT、PATCH、DELETE 。

对资源的操作,无外乎 CRUD(增删改查),RESTful 中,每个 HTTP 动词对应一个 CRUD 操作。

GET:对应 Retrieve 操作(查询操作)POST:对应 Create 操作DELETE:对应 Delete 操作PUT:对应 Update 操作PATCH:对应 Update 操作 2.3 POST 和 PUT 的区别

一般说到 HTTP 动词对应 CRUD 的时候,PUT 都是对应 Update 操作的。但其实,PUT 也可以做 Create 操作。二者的区别在于:

URL:POST 不需要指定到个体,例如新增 user 的接口?POST /api/users。 PUT 的 URL 需要指定到具体的个体,例如?PUT /api/users/1,如果?1?这个 user 存在,则 Update,否则 Create。这个很好理解,POST 确定是新增,insert 的时候是不需要 where 条件的;PUT 则不行,update 的时候不加 where,干过的小伙伴请举手。另外,PUT 的时候,也不是每个 user 就要建一个接口的,这里需要用到的就是路由,一般是写成?PUT /api/users/{id},这样就具有一般性了。路由在这里就不展开讲了。幂等性:PUT 是幂等的,而 POST 是非幂等的。关于幂等性,见下文。 2.4 PATCH 和 PUT 的区别

PATCH 是 2010 后成为的正式 http 方法,它是对 PUT 的补充。在没有 PATCH 之前,都是用 PUT 进行更新操作,这时候我们的接口中通常会有一个逻辑规则,如:如果对象的一个属性值为null,那么就不更新该属性(字段)值,通过这种方式来避免全部覆盖的操作。现在有了 PATCH 就解决了这种判断,在 PUT 操作中不管属性是不是?null,都进行更新,在 PATCH 接口中就对非?null?的进行更新。另外,PATCH 是非幂等的。

2.5 变通的 POST

按照 REST 建议,查询操作要使用 GET 方法,但是实际情况中处理起来比较麻烦,如:报表统计查询,需要传递的参数很多,如果采用 GET 方法,那么接口接收的参数非常多,接口很难看,通常会封装为 java 对象,但 GET 方法又不支持对象传参,所以很蛋疼;

对于这种情况,最简单的方式就是改成 POST 方式,而且很多公司都是这么干的。可见 REST 只是建议,并非强制约束。

补充:幂等性

幂等(Idempotence)本来是一个数学上的概念,定义就不说了,看了头晕。

后来拓展到计算机领域,描述为:

一个操作、方法或者服务,其任意多次执行所产生的影响均与一次执行的影响相同。

一个幂等的方法,使用同样的参数,对它进行多次调用和一次调用,对系统产生的影响是一样的。所以,对于幂等的方法,不用担心重复执行会对系统造成任何改变。

举个例子,用户 X 的手机话费余额为 2 元,他用支付宝给手机充了 100 元话费,如果将这个操作描述为“给 X 的账户余额增加 100 元”那就是非幂等的,重复操作几次运营商就亏大了。但是,如果将这个操作描述为“将 X 的账户余额设置为 102 元”,那这个操作就是幂等的。简单来说:

幂等操作:将账户 X 的余额设置为 102 元;非幂等操作:将账户 X 的余额增加 100 元 RESTful 的其他细节 3.1 命名规则 (1)全部小写,用?_?或?-?线连接。

例如我在上面给出的例子 :

https://api.example.com/add_user 复制代码

之所以不用驼峰命名法,是因为早期的 URI 一般都是表示服务器上的文件路径,而不同服务器对大小写的敏感性是不同的,为了兼容不同服务器所以才规定不能混用大小写字母。

(2)URL 中只用名词指定资源,因为 REST 的核心是资源,而表示资源的词语天然就是名词。(3)资源用复数表示。 3.2 版本

一种方法是在 URL 中添加版本号,例如:

https://api.example.com/v1/users 复制代码

另一种方法是将版本号加在 HTTP 请求头信息的 Accept 字段中,例如:

Accept: version=1.0 复制代码

虽然有很多博客里推荐里说是推荐在 header 里添加版本信息,因为不同的版本表示的资源依然是同一个,所以不应该用不同的 URL。但是以我目前了解到的情况来看,绝大多数公司都是将版本号放在 URL 中的,并且推荐这么做,简单直观。

网上能找到的版本号加在 URL 中的例子,都是如我上例所示的写法。但是 Jack_Zeng 指出,这样写容易有歧义,会让人误以为?v1?也是资源的一部分,一般都是这么写:

https://api.example.com/users?api-version=1 复制代码 3.3 HTTP 状态码

知乎上另一大神对 RESTful 的解释,相比于 Ivony 多了一句话,他用了三句话来描述:

看 Url 就知道要什么看 http method 就知道干什么看 http status code 就知道结果如何

前两句和 Ivony 的是一个意思。这第三句我觉得总结得也很经典。

http 状态码有 100 多种,我们并不需要全部用到,只需要了解其中常用的就可以了

200 – OK – 一切正常201 – OK – 新资源已经被创建204 – OK – 资源删除成功304 – 没有变化,客户端可以使用缓存数据400 – Bad Request – 调用不合法,确切的错误应该在 error payload 中描述401 – 未认证,调用需要用户通过认证403 – 不允许的,服务端正常解析和请求,但是调用被回绝或者不被允许404 – 未找到,指定的资源不存在422 – 不可指定的请求体 – 只有服务器不能处理实体时使用,比如图像不能被格式化,或者重要字段丢失500 – Internal Server Error – 标准服务端错误,开发人员应该尽量避开这种错误

具体restFul接口写法可以参考:

Springboot 最细节全面的接口传参接参介绍,总有你喜欢的一种方式_默默不代表沉默-CSDN博客_springboot接口传入参数


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #http请求工具类 #1