调用第三方服务如何优雅的封装请求响应?

前言

在我们开发过程中,经常会遇到调用一些第三方的请求与响应,如果只是简单的两种请求与响应那么我们只需要去简单的去封装请求头与请求体即可,并且拼接第三方调用的key即可,但是遇到一些流程比较繁琐的调用就显得非常的麻烦了。

而高效的去封装这些服务的请求与响应实体不仅能提高代码的可维护性,还能提升整体的开发效率。在这篇博客中,我们将探讨如何有效地实现这一目标。

目标实现

这里我推荐使用第三方的发送请求的工具就是okhttp,下面是在项目中引入的pom文件

xml 复制代码
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version>
</dependency>

还有就是在请求和响应中需要序列化文件

xml 复制代码
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.5</version>
</dependency>

创建请求方法

这里我们一般会将统一请求的参数(例如:appId,key)等参数统一的封装到这个里面

java 复制代码
private static final String CONTENT_TYPE = "application/json; charset=UTF-8";
/**
 * 发起请求
 * @param path 请求拼接路径
 * @param method 请求类型
 * @param payload 请求体
 * @return 响应体
 */
@NotNull
@SneakyThrows
protected String request(String path, String method, String payload) {
    //获取统一的请求前缀
    String url = getUrl(path);
    String pathAndParameters = url.replace(getUrl(""), "");

    Request.Builder builder = new Request.Builder()
            .url(url)
            .header("X-Tsign-Open-App-Id", appId)
            .header("X-Tsign-Open-Auth-Mode", "Signature")
            .header("X-Tsign-Open-Ca-Timestamp", String.valueOf(System.currentTimeMillis()))
            .header("Date", "")
            .header("Accept", "*/*")
            .header("Content-MD5", contentMD5)
            .header("Content-Type", CONTENT_TYPE);



    RequestBody body = null;
    if (StringUtils.isNotBlank(payload)) {
        body = RequestBody.create(payload.getBytes(), MediaType.parse(CONTENT_TYPE));
    }
    builder.method(method, body);

    Request httpRequest = builder.build();
    Response r = httpClient.newCall(httpRequest).execute();
    if (!r.isSuccessful()) {
        System.err.println("请求异常: r=" + r);
        return null;
    }

    String text = r.body().string();
    return text;
}

通过这段代码我们就可以统一将填充的内容封装到请求当中了。

配置请求参数

我们的请求参数如果是微服务就可以配置参数到配置中心,然后供我们后续使用如下示例:

  • 添加yml配置
yml 复制代码
config:
  appId: 123
  secret: ***
  • 预设配置 创建一个类去接收这些配置
java 复制代码
@Data
@ConfigurationProperties("config")
public class PropertiesConfig{

    /**
     * appId
     */
    String appId;

    /**
     * 密钥
     */
    String secret;

}
  • 用bean的方式在项目启动的时候填充到这个类中
less 复制代码
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties(PropertiesConfig.class)
public class UseAutoConfiguration {

    private final PropertiesConfig properties;

    @Bean
    @ConditionalOnProperty(value = "fastesign.appId")
    FastEsignService esignService() {
    //需要配置的config类
        UseConfig bean = new UseConfig();
        bean.setSecret(properties.getSecret());
        bean.setAppId(properties.getAppId());
        return bean;
    }
  • 预设类 让我们再来看看useConfig中要添加那些属性呢?
java 复制代码
public class UseConfig {
/**
 * appId
 */
@Setter
String appId;

/**
 * 密钥
 */
@Setter
String secret;

为需要注入的方法添加一个set方法,在项目启动的时候将属性注入到里面,然后供上面去调用

Json序列化

因为在服务之间传输基本都是使用的序列化,这里我也直接提供json序列化util工具了,后续我们使用直接调用这些工具类了

typescript 复制代码
//序列化
public static String toJson(Object object) {
    try {
        return objectMapper.writeValueAsString(object);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

//反序列化
public static <T> T parseObject(String text, Class<T> mainType, Class<?> clazz) {
    try {
        JavaType type = objectMapper.getTypeFactory().constructParametricType(mainType, clazz);
        return objectMapper.readValue(text, type);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

封装不同的请求

因为基本都是一些post和get请求所以这里我就拿这两个请求进行演示了,其他的请求都类似这两请求了

还是那上面已经封装好的请求,然后传入我们需要调用请求方法

vbnet 复制代码
@SuppressWarnings("ALL")
public <T> EsignResponse<T> post(String path, Object request, Class<T> clazz) {
    String text = request(path, "POST", JsonUtils.toJson(request));
    return JsonUtils.parseObject(text, EsignResponse.class, clazz);
}


@SuppressWarnings("ALL")
public <T> EsignResponse<T> get(String path, Class<T> clazz) {
    String text = request(path, "GET", null);
    return JsonUtils.parseObject(text, EsignResponse.class, clazz);
}

这里可以看到它的入参出参类都使用了范型,就是为了方便我们去更好的扩展接口

使用

上面基本就是我们封装的一些基本信息了,我们如何去使用呢?

我们只需要去定义好它的入参出参的类然后按照上面的方法给传入即可

typescript 复制代码
/**
 * post示例
 *
 * @param request
 * @return
 */
public EsignResponse<TestResponse> test(TestRequest request) {
    String path = "/v2/url";
    return UseConfig.post(path, request, TestResponse.class);
}

/**
 * get示例
 *
 * @param request
 * @return
 */
public EsignResponse<TestResponse> get(String request) {
    String path = "/v3/url" + request;
    return fastEsignService.get(path, TestResponse.class);
}

总结

通过这些方法,我们可以高效、安全且优雅地与第三方服务交互,从而提升整个应用程序的质量和可靠性。

相关推荐
向前看-7 小时前
验证码机制
前端·后端
超爱吃士力架8 小时前
邀请逻辑
java·linux·后端
AskHarries10 小时前
Spring Cloud OpenFeign快速入门demo
spring boot·后端
isolusion11 小时前
Springboot的创建方式
java·spring boot·后端
zjw_rp12 小时前
Spring-AOP
java·后端·spring·spring-aop
TodoCoder12 小时前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
凌虚13 小时前
Kubernetes APF(API 优先级和公平调度)简介
后端·程序员·kubernetes
机器之心13 小时前
图学习新突破:一个统一框架连接空域和频域
人工智能·后端
.生产的驴14 小时前
SpringBoot 对接第三方登录 手机号登录 手机号验证 微信小程序登录 结合Redis SaToken
java·spring boot·redis·后端·缓存·微信小程序·maven
顽疲14 小时前
springboot vue 会员收银系统 含源码 开发流程
vue.js·spring boot·后端