API对接实战

目录

一 背景

二 了解B公司接口的基础约定

三 基础域名

四 请求及相应格式说明

五 确定要对接哪些API

六 根据API文档,编写一些基础工具类。

七 根据API文档,编写必要的DTO

八 针对每个API方法,进行对接

九 对接代码结构

十 一些对接技巧


一 背景

在平时工作中,经常会遇到的一种场景是:A公司要对接B公司的API方法,这时,A公司就要阅读B公司的接口文档,从接口文档中找到自己需要对接的API,并根据接口文档的要求,完成编码工作,最终完成对接工作。

本篇是站在A公司的角度,去对接B公司API接口的实战。

二 了解B公司接口的基础约定

一般情况下,B公司都会给出以下类似约定来满足基础对接,并且会提供测试环境和正式环境的两套信息。

appkey:A公司商户平台 id

appsecret:A公司商户平台 secret

三 基础域名

一般情况下,B公司会提供测试环境和生产环境两个基础域名。

例如

测试环境 : https://api-b-dev.com.cn

生产环境 : https://api-b-prod.com.cn

四 请求及相应格式说明

一般情况下,B公司会提供请求及相应的基础格式说明。

例如:

1 请求方式

post

2 请求消息格式

application/json

3 响应消息格式

application/json

4 请求公共参数

例如,B公司有以下要求

所有接口均需要以 Http Header 方式传递以下参数;

参数名

描述

必填

appkey

商户平台 id

request_id

请求标识 ,每次请求唯一

sign_type

签名方法,固定为 sha256

signature

签名,算法为 HMACSHA256(appkey+timestamp+appsecret,appsecret)

version

版本, 固定为 2.0

callback_url

回调地址, 以 https://或者 http://开头并进行 base64 编码

是(同步响应的接口可不必填写)

timestamp

时间戳(秒), 30 分钟过期

当然,不同的公司提供的参数各不相同,因公司而异。

5 响应/回调参数说明

例如:B公司所有API都有响应,并且有的API还有回调响应,不论是响应还是回调响应,它们的参数格式都一样。

参数

类型

描述

code

int

状态码

msg

String

消息

request_id

String

请求时的 request_id

data

Object

数据

appkey

String

商户平台id

6 针对异步回调的说明

例如:B公司对异步回调说明如下:

异步回调:

某些特定的接口需要异步返回结果,因此需商户A提供一个回调地址,将其进行base64 编码后,配置在 Http 请求 Header 中的 callback_url 里。

应答机制:

应答机制是指当商户A收到B公司数据通知时,必须回写 success 字符串,不区分大小写,B公司收到该“ success”,便认为商户A已收到通知; 否则会继续重复请求回调接口 3 次, 时间间隔为 1s, 5s, 30s。如果 4 次都访问不通,则会间隔 3h 继续轮询回调。

回调解密:

回调使用 aes 加密,需解密后使用。为避免由于网络波动造成回调失败,长时间未收到回调,请主动查询。

7 请求体加密说明及示例

数据采用AES加密,加密后作为data的值。

示例:

加密前:

{"settlement_code":["JS19BUB14F5D8D4C"],"random_code":["19BUB14F5D8D4C","19BUAD0E89D780"]}

加密后:

{"data":"236agZcupcSsMZghtlmzhb7lEWzGZc3FO5GWQyrSB5kP/y1ESvd+CuBgQiWU/fwAICY/s0mideku/rXSKEb8In41F4SkUVLyLzYoYGed4QTjsqohTM0T6wmbkOiT1TH3"}

对 {"settlement_code":["JS19BUB14F5D8D4C"],"random_code":["19BUB14F5D8D4C","19BUAD0E89D780"]} 进行AES加密,结果为:

236agZcupcSsMZghtlmzhb7lEWzGZc3FO5GWQyrSB5kP/y1ESvd+CuBgQiWU/fwAICY/s0mideku/rXSKEb8In41F4SkUVLyLzYoYGed4QTjsqohTM0T6wmbkOiT1TH3

8 回调解密说明以及示例

数据采用AES解密,解密data值部分,解密后是json字符串

解密前:

{"code":0,""msg":"处理成功","request_id":"47fbb4ce-ae8e-4276-9d4a-4d279c9dfa78","data":"TI6H4Zx7YeWM0dSiial6L+nCvrEv8Oqk1ZFhWXqYZcRzzZyy/xECQW0nfDszpNDmRMlSmsWkBJMmu4a/PmBivUBoNJwFBzAnOfn8gtYKdxDU16lDFwN5d/IW1UJijJ2lU5YkDs/rMTyRN1NTR+0vJ1So0lmeZQiGQWEwE5t4wZykSC3cMQZyvJ952J7KU6aBXv1ZUGncZbWHQQaLw4UxFaBWIO8bVlkBIAqzolswI4dhtqBzFwmdEx+7hzHSeidOVbIja5adgKMAjvIUTdtUEb/cO0ipO6QbK8wglk6dQ8+7rFTchBYIoaaqM9SfhcdvAYuSGk6yHIyN4GEtLBA5Zw==","appkey":"47fbb4ce-ae8e-4276-9d4a-4d279c9dfa78"
}

解密后:

{"code":0,""msg":"处理成功","request_id":"47fbb4ce-ae8e-4276-9d4a-4d279c9dfa78","data":{"settlement_code":"JS19BR19A690E9F9","order_random_code":"09708757-7ea1-4fda","refund_merchant_amount":54736.84,"refund_service_amount":263.16,"change_code":"FW19BRAA9A200255","change_merchant_amount":4263.16,"change_service_amount":236.84},"appkey":"47fbb4ce-ae8e-4276-9d4a-4d279c9dfa78"
}

9 一般公司B还会对code值进行说明。

五 确定要对接哪些API

一般情况下,公司B会针对某个项目提供必要的API,我们往往只需要对接少部分API接口,因此,首先确认要对接哪些API方法。我们只需要按照API的要求进行对接即可。

六 根据API文档,编写一些基础工具类。

工具类分两类。一类工具类,公司B会提供DEMO,我们拿来用即可。另外一类就需要自己根据API要求自己编写了。

1 公司B提供的基础工具类

例如,公司B提供了AES加解密以及签名的工具类

import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;/**
* AES加解密工具
*/
public class EncryptUtil {private static final String CipherMode="AES/CBC/PKCS7Padding";private static final String EncryptAlg ="AES";private static final String Encode="UTF-8";private static final String APPSECRET = "7da8046aa2da46bfb08429058e910081";private static final String AESIV = "ff465fdecc764337";/*** 加密:有向量16位,结果转base64* @param context* @return*/public static String encrypt(String context) {try { //下面这行在进行PKCS7Padding加密时必须加上,否则报错Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());byte[] content=context.getBytes(Encode);Cipher cipher = Cipher.getInstance(CipherMode);cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(APPSECRET.getBytes(Encode), EncryptAlg), new IvParameterSpec(AESIV.getBytes(Encode)));byte[] data = cipher.doFinal(content);String result= Base64.encodeBase64String(data);return result;} catch (Exception e) {e.printStackTrace();}return null;}/*** 解密* @param context* @return*/public static String decrypt(String context) {try {byte[] data=Base64.decodeBase64(context);Cipher cipher = Cipher.getInstance(CipherMode);cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(APPSECRET.getBytes(Encode), EncryptAlg), new IvParameterSpec(AESIV.getBytes(Encode)));byte[] content = cipher.doFinal(data);String result=new String(content,Encode);return result;} catch (Exception e) {e.printStackTrace();}return null;}/*** 生成 HMACSHA256* @param data 待处理数据* @param key 密钥* @return 加密结果* @throws Exception*/public static String HMACSHA256(String data, String key) throws Exception {Mac sha256_HMAC = Mac.getInstance("HmacSHA256");SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");sha256_HMAC.init(secret_key);byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));StringBuilder sb = new StringBuilder();for (byte item : array) {sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));}return sb.toString();}public static void main(String[] args) {//test256();testEncrypt();//testdecrypt();}private static void testdecrypt() {String s1 = "TI6H4Zx7YeWM0dSiial6L+nCvrEv8Oqk1ZFhWXqYZcRzzZyy/xECQW0nf" +"DszpNDmRMlSmsWkBJMmu4a/PmBivUBoNJwFBzAnOfn8gtYKdxDU16lDFwN5d/I" +"W1UJijJ2lU5YkDs/rMTyRN1NTR+0vJ1So0lmeZQiGQWEwE5t4wZykSC3cMQZyvJ95" +"2J7KU6aBXv1ZUGncZbWHQQaLw4UxFaBWIO8bVlkBIAqzolswI4dhtqBzFwmdEx+7hzHSeid" +"OVbIja5adgKMAjvIUTdtUEb/cO0ipO6QbK8wglk6dQ8+7rFTchBYIoaaqM9Sf" +"hcdvAYuSGk6yHIyN4GEtLBA5Zw==";System.out.println(decrypt(s1));}private static void testEncrypt() {String s = "{\"name\":\"小明\",\"certificate_num\":\"451121196209260032\",\"certificate_type\":1,\"phone_num\":\"1388888888\",\"merchant_id\":\"c7c114d5da444df2b5d47a66c9c11111\"}";String afterEncrypt  = encrypt(s);System.out.println(afterEncrypt);}private static void test256() {// 签名算法String s2 = "c7c114d5da444df2b5d47a66c9cbd3fc16010271967da8046aa2da46bfb08429058e910081";String key = "7da8046aa2da46bfb08429058e911111";try {String s1 = HMACSHA256(s2,key);System.out.println(s1);} catch (Exception e) {e.printStackTrace();}}
}

2 根据API要求自己编写的工具类

例如:根据公司B的要求,编写特定的post方法

// 满足公司B的post方法
public static String sendPostByJsonWithHeader(String url, String body, Map<String, String> headers) throws Exception {CloseableHttpClient httpclient = HttpClients.custom().build();HttpPost post = null;String resData = null;CloseableHttpResponse result = null;try {// 封装 url,并且是 post 请求。post = new HttpPost(url);HttpEntity entity = new StringEntity(body, Consts.UTF_8);// 基本配置post.setConfig(RequestConfig.custom().setConnectTimeout(30000).setSocketTimeout(30000).build());// 封装消息头if (null != headers && !headers.isEmpty()) {for (Entry<String, String> entry : headers.entrySet()) {post.setHeader(entry.getKey(), entry.getValue());}}// 消息头支持 jsonpost.setHeader("Content-Type", "application/json");// 封装数据post.setEntity(entity);// 发送请求result = httpclient.execute(post);if (HttpStatus.SC_OK == result.getStatusLine().getStatusCode()) {// 返回结果resData = EntityUtils.toString(result.getEntity());}} finally {if (result != null) {result.close();}if (post != null) {post.releaseConnection();}httpclient.close();}return resData;
}// 生成header的方法
private static Map<String, String> generateHeader(String callbackUrlParam) {Map<String, String> headers = new HashMap<>();// 商户结算平台 id,固定headers.put("appkey", Constant.appkey);// 请求标识 ,每次请求唯一,动态数据String requestID = UUID.randomUUID().toString();headers.put("request_id", requestID);// 时间戳(秒),30 分钟过期,动态数据Date date = new Date();String timestamp = String.valueOf(date.getTime() / 1000);headers.put("timestamp", timestamp);// 签名方法 ,暂支持 sha256headers.put("sign_type", "sha256");// 签名,算法为 HMACSHA256(appkey+timestamp+appsecret),动态生成String signatureStr = Constant.appkey + timestamp + Constant.appsecret;String signature = null;try {signature = EncryptUtil.HMACSHA256(signatureStr, Constant.appsecret);} catch (Exception e) {e.printStackTrace();}headers.put("signature", signature);// 版本, 本文档为 2.0headers.put("version", "2.0");// 回调地址, 以 https://或者 http://开头并进行 base64 编码String callbackUrl = callbackUrlParam;if (callbackUrl != null) {// 需要对callbackUrlParam进行base64 编码,然后赋值给 callbackUrlBase64.Encoder encoder = Base64.getEncoder();byte[] textByte;try {textByte = callbackUrlParam.getBytes("UTF-8");callbackUrl = encoder.encodeToString(textByte);headers.put("callback_url", callbackUrl);} catch (UnsupportedEncodingException e) {e.printStackTrace();}}// 项目编号,暂不支持headers.put("project_code", null);return headers;
}

七 根据API文档,编写必要的DTO

针对每个API,主要包含请求DTO,响应DTO,回调响应DTO,这个就要跟踪API要求,编写满足要求的DTO。

当然有些DTO是可以抽象成一个类,例如一般响应DTO和回调响应DTO都是一样的,这个时候就可以抽象为一个DTO了。

例如:

package GDDto;/**
* @className: GDCommonRes
* @description: 共同响应结果
* @date: 2020/9/24
* @author: cakin
*/
public class GDCommonRes {/*** 状态码*/private int code;/*** 消息*/private String msg;/*** 请求时的 request_id*/private String request_id;/*** 数据*/private String data;/*** appkey*/private String appkey;public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public String getRequest_id() {return request_id;}public void setRequest_id(String request_id) {this.request_id = request_id;}public String getData() {return data;}public void setData(String data) {this.data = data;}public String getAppkey() {return appkey;}public void setAppkey(String appkey) {this.appkey = appkey;}
}

八 针对每个API方法,进行对接

做好以上准备工作,就可以一个个接口进行对接了。可采用下面方式一个一个接口进行对接。

public static void main(String[] args) {// 1. 批量创建结算单    回调接口。// batchSettlement();// 2. 查询结算单       非回调接口。//querySettlement();// 3. 结算单退款       回调接口。refundSettlement();// 4. 授权签约      非回调接口。// authorizSigned();// 5. 获取签约结果     非回调接口。// querySigned();
}

九 对接代码结构

十 一些对接技巧

1 遇到问题,如果需要公司B的帮助,需要主动和公司B的对接人员交流,尽快找到问题所在。

2 有些基础代码,如果公司B能提供,主动要一下,如果确实因为信息安全问题,公司B不方面提供,那就得自己写了,写完后,如果不确定代码是否符合B的要求,可以发给公司B的对接人员看看,以确定代码的正确性。

3 学习公司B的接口文档中好的地方,应用到自己的工作中。

4 委婉指出接口文档中的错误和不足,帮助公司B文档质量改进,这样在对接时,公司B的对接人员也会更热心的帮助你。

5 公司A的对接代码,放到正式代码的test目录中,一来可以方便调用正式代码中的工具类,二来方便将对接代码移植到正式代码中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/25196.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业微信api对接

用的是wxJava&#xff0c;但是wxJava文档真滴不清楚&#xff0c;都是jar全局搜索url/看方法试的。 坑0&#xff1a; 通讯录不仅要开通api&#xff0c;还得开通是“可编辑”不然是“只读”&#xff08;然后还可以设置人员自己编辑后推动事件服务器&#xff09;挺不错的 坑一&a…

WebAPI接口对接

WebAPI接口对接&#xff1a; 提示&#xff1a;此片文章是总结接口对接经验其中包括模型的建立以及统一的调用 学习内容&#xff1a; 数据对象模型的建立如何规范定义模型统一的请求方法系统中model的命名 数据对象的建立 接口的数据传输对象包括Request对象和Response对象 …

百度翻译API对接

百度翻译开发平台&#xff1a;http://api.fanyi.baidu.com/api/trans/product/index 打开如上链接&#xff1a; 下载SDK 导入SDK 新建一个工程&#xff08;zyq-translate&#xff09;&#xff0c;并新建包&#xff08;com.zyq.translate&#xff09; 解压SDK&#xff0c;得…

对接海康ISC平台API

开发文档&#xff1a;海康开放平台。&#xff08;视频预览、抓图等能力&#xff09;

Unity Layer(图层)简介

图层基础 1. 当一个项目或者场景中包含很多对象时&#xff0c;通常难以组织。有的时候&#xff0c;希望一些游戏对象只能被某些摄像机看到或者只会被某些灯光照亮&#xff1b;有时&#xff0c;你可能希望只让某些类型的对象之间发生碰撞&#xff1b;在Unity中用图层处理上述需求…

【闲玩】看看ChatGpt认为的各级别Unity程序该掌握哪些技术

1.初级Unity开发 2.中级Unity开发 3.高级Unity开发 4.资深Unity开发 结语&#xff1a; 仅供娱乐哈&#xff0c;不过还是可以参考的。 不得不说。。。ChatGpt是真的强啊。。。

图形学之Unity渲染管线流程分析

文章来源&#xff1a; 学习通http://www.bdgxy.com/ 普学网http://www.boxinghulanban.cn/ 智学网http://www.jaxp.net/ 表格制作excel教程http://www.tpyjn.cn/ 学习通http://www.tsgmyy.cn/ 下图是《Unity Shader 入门精要》一书中的渲染流程图&#xff1b; ApplicationS…

Unity渲染工程收集

NPR 非真实渲染 UnityURP-AnimeStyleCelShader SSR 屏幕空间反射 UnitySSReflectionURP Skin 皮肤 Unity-URP-SkinSSSLUTGenerator

art-template渲染大坑,从后台接受到的数据正确,但渲染出来的都是空白

问题描述 后台使用的是art-template模板引擎和express // 部分代码如下 router.get(/advert/add, (req, res, next) > {res.render(advert_add.html); });前端使用的art-template 重点看下面画着的部分 // 代码如下 {{ extend ./layout.html }}{{ block style }} {{ /blo…

[Unity3D热更框架] LuaMVC简介

1.什么是LuaMVC 从工作以来一直从事工业三维仿真软件/AR软件的开发&#xff0c;每个项目开发周期短&#xff0c;项目从Demo到完(huang)结(le)时间较为紧凑&#xff0c;因此需要一个便捷的开发框架作为支撑&#xff0c;以适应不同的项目需求&#xff0c;而且需要尽可能覆盖多个终…

一张图了解OpenGL的渲染架构

初学者在初学OpenGL时&#xff0c;很多时候会对OpenGL的渲染架构感到困惑&#xff0c;不清楚它是怎么一个渲染流程&#xff0c;常将Arributes直接传递到片元着色器&#xff0c;或者为了将属性直接传递到片元着色器&#xff0c;而通过uniform传递到片元着色器等&#xff0c;这样…

GacUI:跨平台和渲染器

GacUI&#xff1a;跨平台和渲染器 https://github.com/vczh/GacUIBlog UI库跨平台的方法无非就是每个平台写一次。而如何把更多的共同点抽取出来&#xff0c;尽量的减少每个平台写一次的部分&#xff0c;是每一个跨平台的UI库的重点之一。GacUI的设计比较直接&#xff0c;所有…

Unity3D 《拥挤城市》3D房子建筑透视效果实

3D游戏&#xff0c;经常会看到透视效果&#xff0c;例如《王者荣耀》草丛透视&#xff0c;《拥挤城市》建筑透视。 实现原理&#xff1a;把3D模型MeshRenderer中Materials替换成透明材质球。 举例&#xff1a;《拥挤城市》3D房子建筑透视效果实现&#xff0c;效果如下图&…

Unity2020高清渲染管线

一、高清渲染管线加载与环境配置 这里使用2019.3.0f6版本 1、加载高清渲染管线&#xff08;High Definition RP&#xff09; 2、创建高清管线脚本文件 3、配置高清渲染管线环境&#xff08;把色彩空间改为线性空间&#xff09; 4、把高清渲染管线脚本添加到图形&#xff08;G…

Unity Xlua热更新框架(一):概述与效果演示

1. 资源目录划分 资源&#xff1a;热更新资源和热更新步骤&#xff08;Bundle&#xff09;&#xff0c;&#xff0c;&#xff0c;&#xff0c;资源需要打成Bundle包&#xff0c;通过不重新安装安装包的情况&#xff0c;去更新和替换资源代码&#xff1a;Lua与C&#xff03;的交…

Unity3D教程:实现房产项目中的材质动态切换

在许多典型的房产展示项目当中&#xff0c;经常需要动态地实现例如墙纸、地板等材质的更换以获得不同的展示效果&#xff0c;下面将通过一个简单的教程介绍实现这一功能的关键技术。 首先需要场景中创建一个简易的样品房&#xff0c;样品房里面有一个地面和两面相互垂直的墙壁…

【GAMES-104现代游戏引擎】4、引擎渲染基础(渲染基础数据、全局光照、PBR、阴影)

Lecture04~05 1、光栅化流程2、一丢丢显卡知识3、网格绘制组件&#xff08;Mesh Render Component&#xff09;4、材质5、资源池&#xff08;Resource Pool&#xff09;6、Cluster-Based Mesh Pipeline7、渲染 游戏渲染的挑战 一个场景包含成千上万的GO需要的材质、shader、效果…

重回游戏公平,向游戏打金工作室宣战!

什么是打金工作室&#xff1f; 近几年中国游戏市场持续发展&#xff0c;国产自研精品游戏层出不穷&#xff0c;游戏产业精品化、高质量健康发展趋势稳定。根据中国音数协游戏工委&#xff08;GPC&#xff09;与中国游戏产业研究院发布的《2022年中国游戏产业报告》显示&#xf…

GPT-4 API平替?性能媲美同时成本降低98%,斯坦福提出FrugalGPT,研究却惹争议

来自&#xff1a;机器之心 进NLP群—>加入NLP交流群 Game Changer 还是标题党&#xff1f; 随着大型语言模型&#xff08;LLM&#xff09;的发展&#xff0c;人工智能正处于变革的爆发期。众所周知&#xff0c;LLM 可用于商业、科学和金融等应用&#xff0c;因而越来越多的公…