1、前言
ps:前言有点多,不想浏览的盆友可以直接看第2点
我们的项目是基于springboot前后端分离的单体应用系统(非分布式),在项目中,可能需要调用第三方接口来获取数据,这个时候就需要使用http工具类来发送请求获取数据(这一块网上一大推工具类,这里就不赘述了)。
还有一种情况,就是在业务代码中,去调用当前系统的接口,又不能直接去调用controller层方法(必须是直接调用接口),由于后端系统不是分布式架构的,使用http工具类去调用时,发现必须使用一个账户去模拟登录,然后才可以去调用当前系统的接口,从而获取数据……动手做的时候就感觉很奇怪,调用自己项目的接口,为啥还需要去登录一次?登录一次虽然可以实现,但是弊端太多了,比如会导致该业务接口速度很慢,降低性能,还需要去维护一个账户,等等。。。。。。
后面研究了一下http工具类后,得到了解决方案,本人觉得这是现阶段唯一的解决方案(分布式项目除外)
2、实现思路
- 浏览器发送请求,后端会生成一个sessionID(或者token,token实现原理一致,这里不多说了),再返回给前端进行存储,下次发送请求时,会在请求中带上这个sessionID,从而可以正常访问后端接口
- http工具类其实就是模拟浏览器发送请求,基于第1点,在创建http对象时,我们只需要把sessionID放入到http工具类中,就可以发送请求了
大致思路就是这样子的,是不是很简单?下面上代码
3、实现代码
3.1、导入依赖
<!--JSON转换工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
<!--http客户端-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
3.2、http工具类代码
package com.shuizhu.util;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.util.EntityUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @author 睡竹
* @date 2022年8月30日
*/
public class HttpRequestUtil {
private String DATA_ENCODING = "DataEncoding";
private String CONTENT_TYPE = "Content-Type";
private String APPLICATION_JSON = "application/json";
public CloseableHttpClient httpClient;
public HttpServletRequest request;
public HttpRequestUtil() {}
/**
* 免登录请使用该构造方法创建httpClient对象,
* 调用系统中的接口,不需要再次使用账户密码进行登录,不支持第三方接口
* @param hostIP 这个参数特别重要,为了给请求设置domain,具体看下面第3小点
* @param request 当次前端发起的请求
*/
public HttpRequestUtil(HttpServletRequest request, String hostIP){
//设置http的cookie,把前端请求的sessionID加入到httpUtil中
BasicCookieStore cookieStore = new BasicCookieStore();
BasicClientCookie cookie = new BasicClientCookie("JSESSIONID", request.getSession().getId());
//设置cookie的domain信息,否则sessionID无法生效
//String ipAddr = IpUtils.getIpAddr(request);
cookie.setDomain(hostIP);
/**
* 设置cookie的Path信息,为全局的url,如:如http://shuizhu.com/api/xxx/xxx,该path就是"/api"
* 如果没有该path,下面的代码最好写上
*/
cookie.setPath(request.getContextPath());
cookieStore.addCookie(cookie);
this.request = request;
//生成httpClient
httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
}
/**
* 需要登录的方式,生成httpClient工具对象
* @param loginUrl 登录地址
* @param reqMap 存储账号密码的map,如:
* {
* "userName":"admin"
* ,"password":"123456"
* }
* 创建对象:
* Map<String,Object> reqMap = new HashMap<>();
* reqMap.put("userName","admin");
* reqMap.put("password","123456");
*/
public HttpRequestUtil(String loginUrl, Map<String,Object> reqMap){
String jsonStr=JSONObject.toJSONString(reqMap);
httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(loginUrl);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000).setConnectionRequestTimeout(35000)
.setSocketTimeout(60000).build();
httpPost.setConfig(requestConfig);
httpPost.setHeader(CONTENT_TYPE, APPLICATION_JSON);
httpPost.setHeader(DATA_ENCODING, StandardCharsets.UTF_8.name());
try {
httpPost.setEntity(new StringEntity(jsonStr));
HttpResponse response = httpClient.execute(httpPost);
System.out.println(EntityUtils.toString(response.getEntity()));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 用户发起http请求,这里只演示post类型的请求
* @param url 请求的路径
* @param reqMap 请求的参数
* @return 接口响应的JSON数据
*/
public String doPost(String url, Map<String,String> reqMap){
String jsonStr=JSONObject.toJSONString(reqMap);
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(35000).setConnectionRequestTimeout(35000)
.setSocketTimeout(60000).build();
//设置请求连接参数等
httpPost.setConfig(requestConfig);
//设置请求数据类型为JSON
httpPost.setHeader(CONTENT_TYPE, APPLICATION_JSON);
//设置编码
httpPost.setHeader(DATA_ENCODING, StandardCharsets.UTF_8.name());
CloseableHttpResponse httpResponse = null;
try {
httpPost.setEntity(new StringEntity(jsonStr));
httpResponse = httpClient.execute(httpPost);
HttpEntity entity = httpResponse.getEntity();
return EntityUtils.toString(entity);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (httpResponse != null) {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
3.3、细节点
public HttpRequestUtil(HttpServletRequest request, String hostIP)方法
request参数:是前端调用接口时发起的请求
hostIP:为服务器的domain域,这里必须是后端的地址(不含http://),在前后端分离项目中,这里不能填写前端项目的地址信息,具体例子如下:
- 如:http://127.0.0.1:8080/api/xxx
- hostIP为:127.0.0.1
- 如:http://shuzihu.com/api/xxx
- hostIP为:shuizhu.com
注意:当存在nginx转发时,这里的hostIP必须是转发后的地址
4、案例
4.1、手写两个接口:
package com.shuizhu.controller;
import com.shuizhu.util.HttpRequestUtil;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* @author 睡竹
* @date 2022/8/30
*/
@RestController
public class TestHttp {
/**
*这一项,在实际开发中,应该在配置中心进行维护
*注意,这个值,必须与下面的"http://127.0.0.1:8080/test2"一致,即hostIp为127.0.0.1
*/
private String hostIp = "127.0.0.1";
@PostMapping(value = "/test2")
public String test2() {
return "成功获取啦!";
}
/**
* 测试http工具类免登录
* @param request
* @return
*/
@GetMapping(value = "/test3")
public String test3(HttpServletRequest request) {
HttpRequestUtil util = new HttpRequestUtil(request,hostIp);
//new HashMap<> 表示test2接口无需参数
String s = util.doPost("http://127.0.0.1:8080/test2", new HashMap<>());
return s;
}
}
4.2、调用接口,查看是否能访问test2数据
可以看到,在http工具类未登录情况下,依旧能访问后端接口
在实际开发中,记得把“hostIp”放到配置中心中
圈起来的地址一般也会放到配置中心进行维护
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99575.html