服务之间的通信(原始方式)

在开发中两个服务之间相互调用通常出现在微服务架构中:

(服务注册 -> 服务配置 -> 引入RPC相关依赖 -> 调用请求)但是这一套流程下来对于简单的系统而言有些复杂了,那么这篇文章就通过一些简单的配置,带你去保证服务之间的通信,使用最原始的Http请求去实现服务之间的通信。


项目背景

这两个项目分别都使用了security框架配合Jwt进行权限校验,然后我们模拟swagger一样,只需要在头中添加token即可保证服务之间的联通调用, 所以我们的难点就转移到了如何去获取token了。

css 复制代码
   我们先自定义一下服务服务A是数据来源服务,项目B是请求服务

token获取

这里因为我们的token都是根据用户名和密码,所以在另外一个项目里面请求的时候肯定也是去模仿登录的时候入参账号和密码,然后我们在A系统里面单独开一个角色与账户、密码用于另外一个项目访问使用。

这里一般与自己的项目具体业务有关,这里就不多赘述了,然后们就能拿到与这个角色绑定的相关用户信息了(账号密码)接下来我们准备请求工具包

请求util

我们将请求都封装到一个工具里面方便我们多次调用,这里我用的请求方法是okhttp3fastjson去做相关的请求参数转化。

pom依赖

xml 复制代码
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>${okHttp.version}</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>${fastjson.version}</version>
</dependency>

请求的util,这里我就只演示post请求了

java 复制代码
/**
 * 发送post请求
 */
public static <T> String realNameVerify(String url, T entity) {
    Response response = getResponse(url, entity);
    String respBody = null;
    try {
        respBody = response.body().string();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    TypeReference<CommonResult<?>> typeRef = new TypeReference<CommonResult<?>>() {};
    CommonResult<?> commonResult = JSON.parseObject(respBody, typeRef);
    log.info("请求地址:" + url + ",返回内容:" + respBody);
    if (CommonResultCode.SUCCESS.getCode()==commonResult.getCode()) {
        if (ObjUtil.isNull(commonResult.getData())) {
            return null;
        }
        return commonResult.getData().toString();
    }else if (commonResult.getCode()==CommonResultCode.UNAUTHORIZED.getCode()
            || commonResult.getCode()==CommonResultCode.PERMISSION_EXPIRATION.getCode()){
        log.info("请求过期,重新获取token时间:"+System.currentTimeMillis());
        Map<String, String> map = new HashMap<String,String>(){{
            put("account",SalesConstants.ACCOUNT);
            put("pwd",SalesConstants.PWD);
        }};
        try {
            respBody = Objects.requireNonNull(getResponse(SalesConstants.LOGIN, map).body()).string();
            Authori = (String) JSON.parseObject(respBody, typeRef).getData();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return realNameVerify(url,entity);
    }else {
        throw new RuntimeException(commonResult.getMessage());
    }
}

这里可以看到我定义了一个CommonResult方法对应的是A项目中public CommonResult<String> getToken(@RequestBody) 返回的公共数据,所以我在接收的时候使用了CommonResult<?>这个语法糖可以接受任意的范型,方便我们后续处理

java 复制代码
/**
 * 发送请求
 */
@NotNull
private static <T> Response getResponse(String url, T entity) {
    Response response = null;
    ObjectMapper objectMapper = new ObjectMapper();
    OkHttpClient client = new OkHttpClient();
    log.info("请求地址:"+ url +",请求内容:" + entity);
    try {
        String jsonBody = objectMapper.writeValueAsString(entity);
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Authori-zation", Authori)
                .post(RequestBody.create(MediaType.parse("application/json"), jsonBody))
                .build();
        response = client.newCall(request).execute();
    } catch (IOException e) {
        throw new RuntimeException("crmeb服务异常:", e);
    }
    return response;
}

这里的Authori是我们通过调用请求登录方法获取到的token,这里具体请求项目使用的什么校验方式就修改为什么校验方式,比如我这里就使用的Authori-zation这种校验方式,然后在我代码中可以看到如果登录过期,那么它就会自动去请求登录信息,然后将获取到的token给赋值到一个全局Authori中,方便后续的使用。

在我的代码中还有许多地方都使用了常量,因为在我们请求服务的时候会用到大量请求地址,这里我就统一使用一个常量类对其管理 # 管理url 将一些配置抽离出来到一个单独的类中,方便后续维护,就比如我这里将登录请求的地址账号密码统一都抽取出来到yml中:

yml 复制代码
    url: http://localhost:8080
    account: root
    pwd: root

然后在引入到常量类中

java 复制代码
@Component
public class SalesConstants {

    @Value("${url}")
    private String crmebUrl;

    @Value("${account}")
    private String account;

    @Value("${pwd}")
    private String pwd;

    /** 登录 **/
    public static String LOGIN;
    public static String ACCOUNT;
    public static String PWD;

//    =====================初始化=====================
    @PostConstruct
    public void init() {
        LOGIN = crmebUrl + "/api/admin/get";
        ACCOUNT = account;
        PWD = pwd;
    }

}

因为我们在使用的时候是直接使用的static修饰的静态方法,而我们使用Value或者其他注入方式注入的时候只能注入到普通的方法中,所以这里我们添加了init方法如上将获取到的值赋值给静态变量。同样的如果还有其他的请求方法需要加入到这里,也可以模仿上面的实现如下:

java 复制代码
String data = realNameVerify(SalesConstants.GET_CUSTOMER, request);
TypeReference<<UserResponse>> typeRef = new TypeReference<<UserResponse>>() {};
return JSON.parseObject(data, typeRef);

我们拿到请求的body之后,再次使用TypeReference这个方法转化为我们需要的UserResponse类,参考我这种写法

总结

如果有帮助到大家请留下你们的小爱心,感谢支持

相关推荐
小旭Coding11 分钟前
卧靠!Go 传给前端的 int64 竟然变成了这个?
后端
用户2986985301412 分钟前
Word 文档文本查找与替换的 Java 实现方案
java·后端
kunge201315 分钟前
深度剖析Claude Code 的CLAUDE.md加载逻辑
后端·vibecoding
米沙AI16 分钟前
MSYS2 快速使用版本
后端
Csvn25 分钟前
Docker 进阶 — 网络模型、数据持久化与多阶段构建
后端
用户42792540517129 分钟前
《微博开放平台官方CLI开源了:70+API一行搞定,AI Agent原生支持》
后端
Csvn30 分钟前
文本处理三剑客 — grep、sed、awk 实战精讲
后端
sarasuki32 分钟前
JavaScript的对象、new的机制与原型包装类
javascript·后端
某鹏36 分钟前
java伪共享问题的稳定解法
后端