api接口开放平台推荐,健康码API接口开放平台

七野 620 2022-11-08

本文关于api接口开放平台推荐,健康码API接口开放平台

很高兴又和各位见面啦,这次我想和你们聊聊api接口开放平台推荐(api网关设计原则);精心为你准备的干货,以及的内容,其实这篇内容对于新手来说还是比较重要的,因为涉及的也比较多,如果你认真看了肯定会有一些收获!

今天准备谈下ESB服务总线和API网关产品的集成和融合分析。

先谈下背景,在前面我写过多篇企业传统IT架构微服务架构转型的文章,中间也分析过API网关产品和ESB服务总线产品的区别。而实际上可以看到企业进行微服务架构转型,往往都是一个逐步迁移和过渡的过程。

而对于企业遗留IT环境,由于涉及到的遗留系统消息,协议,数据复杂,往往已经使用了类似ESB服务总线产品进行业务系统之间的应用和数据集成。而实际在转型中往往一个遗留系统可能会完全重新采用微服务架构框架体系进行建设,而这个微服务应用中也涉及到API集成的问题,这种API集成往往会采用更加轻量高效的API网关来完成。

很多时候我们在谈到微服务的时候,都会说到ESB服务总线已经过时,但是实际上对于大的企业存在大量遗留IT系统建设和集成的场景下,一定会存在ESB服务总线和API网关两种集成产品共存和协同的一段周期来完成过渡。

因此今天准备从几个方面来讲解下ESB和API网关的集成和协同。

1.从产品规划层面,对ESB总线和API网关两种产品集成

2.从企业IT存在遗留和微服务两种应用场景下的集成

3.在准备迁移到完整微服务后,对API网关本身的适配能力提升

下面将分别从这三个方面进行介绍。

对ESB总线和API网关两类产品的整合

对于我们从10年开始进行自研ESB服务总线的研发,从最早的完全自研,到13年底我们重新启动基于开源的SercieMix和Camel规则引擎进行定制开发。在这几年中重点也是对SOA服务开发设计,服务全生命周期管理,SOA管控治理等能力进行完整。

整体的ESB总线的产品架构图如下:


而对于API网关,我们则是基于开源的Kong网关进行定制开发。

当前Kong网关也是大家采用比较多的一个开源API网关产品,底层基于Ngnix和OpenRestry,语言是Lua语言,最重要的是整个架构设计中的可插拔的插件机制,这种插件机制很方便我们自定义插件扩展。比如我们现在对于安全,日志,运行监控等功能都能够很方便的通过插件扩展来实现。

当然你也能够看到对于ESB总线本身也可以完全兼容API网关产品有的对Http Rest接口注册接入,安全,日志,流控等功能要求。但是ESB总线整体还是偏重,如果是一个完整的微服务架构应用环境,我们还是推荐直接采用API网关来实现。

基于上面分析,我们看到。

对于ESB总线和API网关都是底层的进行SOA服务和API接口集成的底层引擎。而对于SOA服务全生命周期管理,服务运行监控,能力开放等业务场景和功能需求是完全可以整合为一套的。这也是我们在进行产品规划和设计的时候重点考虑的内容,即将引擎能力和管控治理能力分离,将管控治理能力进行共性化整合设计。

基于以上思路我们对整个架构进行整合如下:


可以看到,在这种集成架构下,微服务整体应用系统中所有的需要和遗留系统交互的接口全部首先接入和注册到API网关,同时API网关暴露的服务进一步集成和注册到ESB服务总线,形成两级服务集成的方式。

在这种两级服务集成模式下好处包括

  • 微服务应用体系里面的各个微服务仅仅需要暴露特定的API接口到网关和ESB

  • 内部微服务间的Rest API交互仍然可以走注册中心,而且对外透明

  • 可以进一步使用ESB总线协议转换和适配能力,完成SOAP和Rest接口转换和适配

虽然两级集成模式下增加了一定的性能损耗,也拉长了整个服务调用链路。但是在新旧架构并存的过程中,这种两级集成仍然是我们推荐采用的方式。既满足了微服务应用内部的微服务治理要求,又实现了和外围系统间的集成。

如果站在微服务应用角度来看,那么我们完全可以将外部遗留系统都作为对微服务通过API网关暴露的接口的消费方,不同点仅仅在于这些对API网关发起的消费都统一通过ESB服务总线进行了路由和中转。

通过ESB总线代理的作用一方面是实现对所有接口的管控治理,另外一个重点就是解决老接口协议调用方式和新接口之间的适配和转换问题,如下图:


基于这个思路,遗留系统逐步迁移和消亡,那么ESB总线也准备消亡被API网关或微服务治理平台代替。在整个过程中,我们可以逐步提升API网关的协议转换适配能力,以加快对ESB总线的替代操作。

对API网关接口适配能力提升



最后谈下API网关如何提升接口适配能力。

API网关提供的接口适配,虽然不会像ESB服务总线那样提供各种复杂的适配器,但是一些经常会使用到的适配能力还是需要提供,以方便实现API接口的快速开发和接入能力。

最常见的-Http Rest API接口服务的代理接入能力

对于Http Rest API接口服务接入是API网关提供最常见的接口服务接入和适配能力,这里面一种是存代理方式接入或透传,一种是在接入过程中还需要进行适度的数据裁剪和数据丰富。不论是哪种接入,都可能存在在接入过程中增加API网关标准管控所需要的类似SysID,Token等信息。

DB数据库的适配接入

即当前一些API网关会提供的,可以将DB数据库表快速的发布为Rest接口服务,常见的包括了数据库表对象的CRUD主流操作。同时我们看到,完全可以实现一个通用的Http Rest接口服务,对所有的数据库表实现类似的操作能力,但是本身也存在安全管控的风险。

第二种是提供一个类似Sql模糊查询的关联查询接口服务接入能力,即模糊动态查询条件,对于查询结果可能是后台多个表的关联查询,对于具体的查询Sql由用户自己定义。

第三种也是经常会遇到的就是,对于复杂业务对象直接发布为Rest接口服务,一个复杂业务对象实际是后台数据库多张数据库表构成,表之间可以是一种层次结构,也可能是一种关联结构。对于这种方式,当前一般的API网关实际上并不支持,但是实际是经常会遇到的一个DB数据库快速接入和适配的场景。

遗留SOAP-WS接口自动转换为Http Rest接口

对于遗留的SOAP WS服务接口,应该提供快速的服务适配和接入能力,即将SOAP接口自动转换为一个Rest API接口服务接入,同时将消息报文结构由XML转换为XML或Json数据结构。

服务编排和组合服务接入

这个是主流的API网关也会通过的服务注册接入能力,即将已有的多个API服务接口进行服务组合和组装,变成一个组合服务再发布出去,在这个过程中完成多个服务的整合和数据映射,这个在前面多篇文章里面都谈到了服务编排的关键点。

对于服务编排和组合接入,一般还是需要提供可视化的服务编排设计器来完成服务编排接入。服务编排的场景即场景的服务串联,服务组合,服务合并和拆分。

消息中间件的消息接口发布为Http Rest接口

这个也是API网关应该提供的一个API接口服务快速发布的能力,即将已有的消息中间件的消息接口快速发布为一个Http Rest接口服务。即调用API接口将数据写入到消息中间件而不是数据库,对于消息的订阅则仍然可以走传统的JMS消息订阅接口进行。

健康码API接口开放平台

需求:

最近在做数据上传的项目,请求第三方数据上传接口时,需要调用单独的接口获取权限appToken。


接口输入参数由公共输入参数commonIn和请求参数req(第三方数据上传接口的参数)组成,输出参数由公共输出参数commonOut和响应参数rsp组成;


{

    "commonIn": {

        "appToken": "11fd722a113969bf2480fe4781fc7234",

        "requestId": "A37FA9D0D0DF432B9D367B16AEEDE77A",

        "hospitalId": "10086",

        "timestamp": "1525392000",

        "channelNum": 0,

        "sign": "Q5vp1tdaHjuQpDK8yuDOAzFKTOQs5PxgzhLbxMpnadE="

    },

    "req": {

        ......//请求参数 (上传接口的参数)

    }

}


之前看第三方文档不多,因此,在对接获取接口调用凭证appToken接口时,输入参数中sign签名不知道从哪获取,还在对接群问问腾讯开发人员,体现出自己的不专业,写篇文章记录一下对接的过程。


微信电子卡开放平台


我们在第三方对接时,要先看开发指南,对平台和一些规则做初步的了解,不懂的地方标记下来,最后统一咨询平台的开发人员。


基本术语

● HTTPS:超文本传输安全协议(Hypertext Transfer Protocol Secure,常称为HTTP over SSL)是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包;


● JSON:JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式;


● appId:由健康卡开放平台分配给各个ISV的用户凭证;


● appSecret:由健康卡开放平台分配给各个ISV的用户凭证密钥;


● appToken:通过appId和appSecret向健康卡开放平台换取接口调用凭证;


● wechatCode:微信身份码wechatCode唯一标识一个微信帐号,用于在开放平台建卡;


● healthCode:健康卡授权码healthCode对应一张健康卡,用户获取对应健康卡的信息。


获取接口调用凭证appToken接口

接口地址:

https://p-healthopen.tengmed.com/rest/auth/HealthCard/HealthOpenAuth/AuthObj/getAppToken


该接口用于获取接口调用凭证appToken,appToken是 公共参数commonIn 参数之一,是全局唯一接口调用凭据,开发者需要进行妥善维护。


appToken的生成及使用方式说明:


通过该接口获取appToken时,appToken参数不校验,可以为空;


appToken有效期7200秒,需定时刷新,重复获取将导致上次获取的appToken失效;


建议开发者使用中控服务器统一获取和刷新appToken,其他业务逻辑服务器所使用的appToken均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致appToken覆盖而影响业务;


中控服务器需要根据7200秒有效时间提前获取新appToken,为了保持平滑过渡,最近刷新的两个appToken均有效,且次新appToken将在5分钟后失效;


开发时需要做好appToken缓存策略,每7200秒有效时间定时获取,期间接口调用时均使用缓存的appToken,不要每次调用接口时都重新获取;


输入参数:


请求参数req说明:


参数名称     参数代码 必选 类型              说明

ISV用户凭证 appId   是    string 开放平台官网分配的appId


{

    "commonIn":

    {

        "appToken": "",

        "requestId": "E856812660584E208D7421E1CAACE8C3",

        "hospitalId": "10086",

        "timestamp": "1525392000",

        "channelNum": 0,

        "sign": "Q5vp1tdaHjuQpDK8yuDOAzFKTOQs5PxgzhLbxMpnadE="

    },

    "req":

    {

        "appId": "d7656ef9ab5eb27c01724cd3707xxxxx"

    }

}


缓存:采用的map做缓存+定时任务每2个小时重新刷新一次


我们在看第三方文档时会发现,提供不同语言的实例,我想也是为了我们提供开发效率。



在对接时,主要是获取接口参数的签名,平台也会提供代码示例。


签名规则

开放平台会校验调用接口的签名参数sign,因此ISV需要严格按照规则生成,否则会报签名错误。


签名参数sign由公共参数commonIn+请求参数req+appSecret按照一定的规则生成。以获取接口调用凭证appToken接口为例,调用这一接口的输入参数如下所示,其中appToken、sign等为空值的参数不参与签名。


输入参数示例(无签名):


{

"commonIn":{

"appToken":"",

"requestId":"DB4D975748A84309977EA25224C0F5CF",

"hospitalId":"90003",

"timestamp":"1525392000",

        "channelNum": 0,

"sign":""

},

"req":{

"appId":"a1a2e0bde41574ad8ea9a4bb58022oop"

}

}


1、对参数排序

首先需要对所有参数按参数名做 字典序升序 排列,上述示例参数的排序结果为:


{

     "appid":"a1a2e0bde41574ad8ea9a4bb58022oop",

     "channelNum": 0,

     "hospitalId":"90003",

     "requestId":"DB4D975748A84309977EA25224C0F5CF",

     "timestamp":"1525392000",

 }


所谓字典序升序排列,直观上就如同在字典中排列单词一样排序,按照字母表或数字表里递增顺序的排列次序,即先考虑第一个“字母”,在相同的情况下考虑第二个“字母”,依此类推。


注意:批量注册健康卡接口中,请求参数含有嵌套的JSON字段,也需要按参数名做进行 字典序升序 排列。


2、拼接签名原文


将上一步排序好的请求参数格式转化成 参数名称=参数值 的形式,如其参数名称为appId,参数值为a1a2e0bde41574ad8ea9a4bb58022oop,因此格式化后就为appId=a1a2e0bde41574ad8ea9a4bb58022oop。


将上述示例参数拼接后的签名原文为:


appId=a1a2e0bde41574ad8ea9a4bb58022oop&channelNum=0&hospitalId=90003&requestId=DB4D975748A84309977EA25224C0F5CF&timestamp=1525392000

1

3、生成签名串

将上一步中获得的签名原文与appSecret进行字符串拼接,即:签名原文+appSecret,然后使用 SHA256算法 对其加密,将生成的签名串(字节数组)使用 Base64 编码,即可获得最终的签名串。


伪代码如下:


签名原文 = "appId=a1a2e0bde41574ad8ea9a4bb58022oop&channelNum=0&hospitalId=90003&requestId=DB4D975748A84309977EA25224C0F5CF&timestamp=1525392000"

签名 = Base64(SHA256("appId=a1a2e0bde41574ad8ea9a4bb58022oop&channelNum=0&hospitalId=90003&requestId=DB4D975748A84309977EA25224C0F5CF&timestamp=15253920008c8e763f443ef983ac33aef1c7085cfb"))


最终得到的签名串为:


Ar2jTk5vw7iiGkHFLcWfsUrekRoFrTCMXPJg92b32n4=

1

4、生成最终的输入参数

将上一步获取的签名串放入**获取接口调用凭证appToken输入参数(无签名)**中,最终结果如下:


{

"commonIn":{

"appToken":"",

"requestId":"DB4D975748A84309977EA25224C0F5CF",

"hospitalId":"90003",

"timestamp":"1525392000",

        "channelNum": 0,

"sign":"Ar2jTk5vw7iiGkHFLcWfsUrekRoFrTCMXPJg92b32n4="

},

"req":{

"appId":"a1a2e0bde41574ad8ea9a4bb58022oop"

}

}


使用最终的输入参数调用开放平台的获取接口调用凭证appToken接口即可。


JAVA签名DEMO代码示例:

import com.alibaba.fastjson.JSON;

import com.alibaba.fastjson.JSONObject;

import com.alibaba.fastjson.serializer.SerializerFeature;

import java.math.BigDecimal;

import java.math.BigInteger;

import java.security.MessageDigest;

import java.util.*;


public class SignDemo {


    public static void main(String[] args) {

        

        //appSecret

        String appSecret = "8c8e763f443ef983ac33aef1c7085cfb";


        // 示例:获取接口调用凭证appToken接口的完整请求参数如下

        String reqParams = "{" +

                "    \"commonIn\":{" +

                "        \"appToken\":\"\"," +

                "        \"requestId\":\"DB4D975748A84309977EA25224C0F5CF\"," +

                "        \"hospitalId\":\"90003\"," +

                "        \"timestamp\":\"1525392000\"," +

                "        \"sign\":\"\"" +

                "    }," +

                "    \"req\":{" +

                "        \"appId\":\"a1a2e0bde41574ad8ea9a4bb58022oop\"" +

                "    }" +

                "}";


         //构造当前时间戳

        long time = System.currentTimeMillis();

        String nowTimeStamp = String.valueOf(time / 1000);

        

        //构造requestId

        String requestId = UUID.randomUUID().toString().replaceAll("-", "");

               

        JSONObject jsonObject = JSON.parseObject(reqParams);


        Map<String, Object> commonIn = jsonObject.getJSONObject("commonIn");

        //commonIn.put("timestamp", nowTimeStamp);

        //commonIn.put("requestId", requestId.toUpperCase());

        Map<String, Object> req = jsonObject.getJSONObject("req");

        

        // 生成原始签名串

        SortedMap<String, Object> treeMap = new TreeMap<>();

        treeMap.putAll(commonIn);

        treeMap.putAll(req);

        String rawStr=getParamsFromMap(treeMap);

        

        // 生成签名

        String sign = generateSign(rawStr, appSecret);

        System.out.println(sign);

    }


    /**

     * 对请求参数进行排序拼接(含嵌套的JSON字符串),生成待签名字符串

     *

     * @param map

     * @return

     */

    private static String getParamsFromMap(SortedMap<String, Object> map) {

        // sign不参与签名

        map.remove("sign");

        StringBuilder sb = new StringBuilder();

        Set es = map.entrySet();

        Iterator it = es.iterator();

        while (it.hasNext()) {

            Map.Entry entry = (Map.Entry) it.next();

            String k = entry.getKey().toString();

            Object objVal = entry.getValue();

            if (objVal == null) { //值为空的参数不参与签名

                continue;

            }

            String v;

            if (isBaseDataType(objVal.getClass())) {

                v = objVal.toString();

            } else {

                v = JSON.toJSONString(objVal, SerializerFeature.MapSortField);

            }

            if (!v.equals("")) {

                if (it.hasNext()) {

                    sb.append(k).append("=").append(v).append("&");

                } else {

                    sb.append(k).append("=").append(v);

                }

            }

        }

        return sb.toString();

    }


    private static boolean isBaseDataType(Class clazz) {

        return (clazz.equals(String.class) || clazz.equals(Integer.class) || clazz.equals(Byte.class)

                || clazz.equals(Long.class) || clazz.equals(Double.class) || clazz.equals(Float.class)

                || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)

                || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class) || clazz

                .isPrimitive());

    }


    /**

     * Base64(sha256(rawStr + appSecret))进行签名

     * @param rawStr     原始字符串

     * @param appSecret  密钥

     */

    private static String generateSign(String rawStr, String appSecret) {

        try {

            // 先用sha256加密

            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");

            sha256.update((rawStr + appSecret).getBytes("utf-8"));


            // 再用base64编码

            return Base64.getEncoder().encodeToString(sha256.digest());

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

}


总结:

其实对接下来并不难,刚开始想着接口签名加密比较困难,但是对接完之后,再回头看走过的弯路是可以规避的,不用再问对方很多问题,以后再对接类似的项目先看文档,通读3遍第三方接口文档,不懂的问题再问。

上述就是小编为大家整理的api接口开放平台推荐,健康码API接口开放平台

国内(北京、上海、广州、深圳、成都、重庆、杭州、西安、武汉、苏州、郑州、南京、天津、长沙、东莞、宁波、佛山、合肥、青岛)APISpace数据接口平台分析、比较及推荐

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【不懂就问】CPU 到底是怎么识别代码的?
下一篇:采用SED1356显示控制芯片实现液晶显示接口设计
相关文章

 发表评论

暂时没有评论,来抢沙发吧~