我经历的几个公司,几乎都有外部接口需要我们进行对接,有的第三方给我们提供相关API,我们采用API直接调用即可,但是实际上,大部分公司内部的文档是一言难尽的。但是学习本身就是一个建模的过程!我来分享一下,我对外部接口对接的相关理解。
接口地址
接口地址本来没什么可说的,但是我们开发可能会有多个环境,一般分为dev、release环境。代码运行环境变化,实际只是Host发生变更。
目前我自己的方式是:在配置中心定义一个配置Base.Host=XXXXX。然后实际接口是项目启动时:对相关的接口地址进行拼接后缀:如 String baiduUrl = BaseHost + ”/zanglikun.com“; 如果配置发生变更,我们在写一个方法,去执行重新赋值baiduUrl。这样有个好处是:如果接口多,只需要更改一个配置,就能实现全局替换Host。例如:
@Data
@Component // 注册为组件
@Slf4j
public class TelecomApiConstant {
// 定一个基础的host
public static String BASE_HOST = "http://127.0.0.0:27010";
// 接入一个动态替换的Host
@Value("${telcom.host}")
private String Base_Host_inConfig;
// 本方法实际是制定配置文件发生了变动,调用setBaseHost() 实现动态切换
@ApolloConfigChangeListener("application")
public void changeConfig(ConfigChangeEvent changeEvent) {
log.info("【Apollo配置文件】:发送变动了!");
ConfigChange change = changeEvent.getChange("telcom.host");
if (Objects.nonNull(change)) {
Base_Host_inConfig = change.getNewValue(); // 替换新的配置值
setBaseHost(); // 调用此方法替换其他BaseHost。这样就实现了动态切换环境了
}
}
// 项目启动的时候 给相关接口赋值。同时也是个替换最新URL的方法
@PostConstruct
public void setBaseHost() {
BASE_HOST = Base_Host_inConfig;
// 获取边界数据
GET_REGIONAL = BASE_HOST + "/api/datacenter/v1/gridViews/getRegional";
}
// 获取边界数据
public static String GET_REGIONAL = BASE_HOST + "/api/datacenter/v1/gridViews/getRegional";
}
第二种方式是:配置中心写全了全部配置 比如 baiduAPI.searchName = https://www.baidu.com/zanglikun.com 这样有个好处是:针对每个接口,可单独控制环境。如果你有频繁切换接口环境的情况,可能就得人工切换了。本来想是全部替换 比如将 www.baidu.com 替换为 www.dev.baidu.com 去实现全部接口的切换。但是实际上,如果你配置有www.baidu.com字眼,可能会被同步替换,实际我不是太喜欢这种方式。
接口入参
我们先考虑到接口传参方式:如果你的接口有附件上传,就得使用请求头当放入application/form-data。详情可见https://www.zanglikun.com/13608.html说明。
如果入参只是文本文件,那就无所谓了。按照目标接口要求的Header、Body即可!
接口返回值
大部分接口返回的内容不会以Http请求的状态码给我们作为评判接口是否有效的结果。比如一个接口HTTP状态码是:200 。但是接口返回:{"success":false,"data":"","error_message":"account为空"}。这个场景肯定不能算所接口有效了!
所以想通过Http请求的状态码不是一个好方式。最终还得以具体业务接口响应的标志,如:code或者success相关字样为准。
{
"success": true,
"errCode": null,
"errMessage": null,
}
接口响应数据转为我们需要的Java集合、对象
接口响应的Response对象的内容我们只需要:
String res = response.body().string();
它本身就是一个文本
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
}
结果处理如下
Object data = JSONUtil.parseObj(s).get("data");
List<Inspection> inspections = JSONUtil.toList(list.toString(), Inspection.class);
CommunityBaseInfoVO baseVo = JSONUtil.toBean(data, CommunityBaseInfoVO.class);
请求日志
调用第三方接口一定要在工具类封装时:加上日志
请求头、请求体、响应结果。这是调用第三方接口必须要加入的。后续出现问题,也能迅速发现入参有问题,出参有问题!可以节省大量的排查问题的成本!
这是我从慧摩尔改造出来的工具类,使用的是OKHTTP
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.exception.ExceptionUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Copy By Huimor-Project
*/
@Slf4j
public class HttpUtils {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static OkHttpClient client;
static {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
client = builder.callTimeout(20, TimeUnit.SECONDS).build();
}
/**
* HTTP POST JSON请求
*
* @param url 请求路径
* @param jsonBody 请求参数
* @param headers 请求头
* @return 响应数据
*/
public static String httpPostJsonRequest(String url, String jsonBody, Map<String, String> headers) {
log.info("httpPostJsonRequest url: {}", url);
log.info("httpPostJsonRequest params: {}", jsonBody);
log.info("httpPostJsonRequest headers: {}", headers);
RequestBody body = RequestBody.create(JSON, jsonBody);
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json;charset=utf-8")
.build();
if (null != headers && !headers.isEmpty()) {
Request.Builder builder = request.newBuilder();
for (Map.Entry<String, String> entry : headers.entrySet()) {
builder.addHeader(entry.getKey(), null == entry.getValue() ? "" : entry.getValue());
}
request = builder.build();
}
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
if (response.body() == null) {
log.error("httpPostJsonRequest service return null");
}
String responseText = response.body().string();
log.info("httpPostJsonRequest response: {}", responseText);
return responseText;
} else {
response.close();
log.error("httpPostJsonRequest request was aborted");
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return null;
}
/**
* get 请求
*
* @param url
* @return
*/
public static String get(String url) {
Request request = new Request.Builder()
.url(url)
.build();
try {
Response response = client.newCall(request).execute();
log.info("send request URL:{}" , url);
if (response.isSuccessful()) {
if (response.body() == null) {
log.error("httpPostJsonRequest service return null");
}
String responseText = response.body().string();
log.info("get response: {}", responseText);
return responseText;
} else {
response.close();
log.info("get request was aborted");
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return null;
}
/**
* get 请求
*
* @param url
* @return
*/
public static String get(String url,HashMap<String, String> headers) {
Request request = new Request.Builder()
.url(url)
.build();
if (null != headers && !headers.isEmpty()) {
Request.Builder builder = request.newBuilder();
for (Map.Entry<String, String> entry : headers.entrySet()) {
builder.addHeader(entry.getKey(), null == entry.getValue() ? "" : entry.getValue());
}
request = builder.build();
}
try {
Response response = client.newCall(request).execute();
log.info("send request URL:{}" , url);
if (response.isSuccessful()) {
if (response.body() == null) {
log.error("httpPostJsonRequest service return null");
}
String responseText = response.body().string();
log.info("get response: {}", responseText);
return responseText;
} else {
response.close();
log.info("get request was aborted");
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return null;
}
/**
* 重载方法 以便于懒省事,JSONUtil.toJsonStr(bodyParam)
*
* @param url 请求路径(String)
* @param bodyParam 请求体(Object)
* @param headers 请求头(HashMap)
* @return 响应结果
*/
public static String httpPostJsonRequest(String url, Object bodyParam, HashMap<String, String> headers) {
log.info("httpPostJsonRequest url: {}", url);
log.info("httpPostJsonRequest params: {}", bodyParam);
log.info("httpPostJsonRequest headers: {}", headers);
RequestBody body = RequestBody.create(JSON, JSONUtil.toJsonStr(bodyParam));
Request request = new Request.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json;charset=utf-8")
.build();
if (null != headers && !headers.isEmpty()) {
Request.Builder builder = request.newBuilder();
for (Map.Entry<String, String> entry : headers.entrySet()) {
builder.addHeader(entry.getKey(), null == entry.getValue() ? "" : entry.getValue());
}
request = builder.build();
}
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
if (response.body() == null) {
log.error("httpPostJsonRequest service return null");
}
String responseText = response.body().string();
log.info("httpPostJsonRequest response: {}", responseText);
return responseText;
} else {
response.close();
log.error("httpPostJsonRequest request was aborted");
}
} catch (IOException e) {
log.error(ExceptionUtils.getStackTrace(e));
}
return null;
}
}
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取全部资料 ❤