http工具类免登录调用当前系统的接口(session方式,可以拓展为token方式),以及调用第三方接口,手动给httpClient设置cookie

1、前言

ps:前言有点多,不想浏览的盆友可以直接看第2点

我们的项目是基于springboot前后端分离的单体应用系统(非分布式),在项目中,可能需要调用第三方接口来获取数据,这个时候就需要使用http工具类来发送请求获取数据(这一块网上一大推工具类,这里就不赘述了)。

还有一种情况,就是在业务代码中,去调用当前系统的接口,又不能直接去调用controller层方法(必须是直接调用接口),由于后端系统不是分布式架构的,使用http工具类去调用时,发现必须使用一个账户去模拟登录,然后才可以去调用当前系统的接口,从而获取数据......动手做的时候就感觉很奇怪,调用自己项目的接口,为啥还需要去登录一次?登录一次虽然可以实现,但是弊端太多了,比如会导致该业务接口速度很慢,降低性能,还需要去维护一个账户,等等。。。。。。

后面研究了一下http工具类后,得到了解决方案,本人觉得这是现阶段唯一的解决方案(分布式项目除外)

2、实现思路

  1. 浏览器发送请求,后端会生成一个sessionID(或者token,token实现原理一致,这里不多说了),再返回给前端进行存储,下次发送请求时,会在请求中带上这个sessionID,从而可以正常访问后端接口
  2. 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”放到配置中心中

圈起来的地址一般也会放到配置中心进行维护 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

睡竹

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

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

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

打赏作者

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

抵扣说明:

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

余额充值