【转载】微服务架构中 API 的开发与治理

微服务 0 1186
张超
张超 管理员 关注 2021年8月18日 18:15 编辑
<div id="page-content" style="padding-top: 32px; color: rgb(51, 51, 51); font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 16px; letter-spacing: 0.544px;"><div style="margin-right: auto; margin-left: auto; max-width: 677px;"><div id="img-content" style="position: relative; zoom: 1;"><h2 id="activity-name" style="margin-top: 0px; margin-bottom: 14px; font-size: 22px; line-height: 1.4;">微服务架构中 API 的开发与治理</h2><div id="meta_content" style="margin-bottom: 22px; line-height: 20px; font-size: 0px; overflow-wrap: break-word; hyphens: auto; position: relative; z-index: 1;"><span style="margin-right: 10px; margin-bottom: 10px; display: inline-block; vertical-align: middle; font-size: 15px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); color: rgba(0, 0, 0, 0.3);">苏槐</span>&nbsp;<span id="profileBt" style="margin-right: 10px; margin-bottom: 10px; display: inline-block; vertical-align: middle; font-size: 15px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); position: relative;"><a href="javascript:void(0);" id="js_name" style="color: rgb(87, 107, 149); -webkit-tap-highlight-color: rgba(0, 0, 0, 0); cursor: pointer;">InfoQ</a></span>&nbsp;<span id="publish_time" style="margin-right: 10px; margin-bottom: 10px; display: inline-block; vertical-align: middle; font-size: 15px; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); color: rgba(0, 0, 0, 0.3);">2017-09-07</span></div><div id="js_content" style="overflow: hidden; font-size: 17px; overflow-wrap: break-word; hyphens: auto; text-align: justify; position: relative; z-index: 0; visibility: visible;"><section style="max-width: 100%; color: rgb(63, 63, 63); font-size: 14px; font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif; text-align: center; overflow-wrap: break-word !important;"><section style="max-width: 100%; text-align: left; overflow-wrap: break-word !important;"><br></section><section style="margin-top: 13px; padding-left: 14px; max-width: 100%; color: rgb(145, 145, 145); text-align: left; line-height: 1em; overflow-wrap: break-word !important;">作者|苏槐</section><section style="margin-top: 13px; padding-left: 14px; max-width: 100%; color: rgb(145, 145, 145); text-align: left; line-height: 1em; overflow-wrap: break-word !important;">编辑|田光</section><section style="margin-top: 40px; margin-right: 8px; margin-left: 8px; padding: 19px; max-width: 100%; font-size: 15px; text-align: justify; line-height: 27px; color: rgb(89, 89, 89); background-color: rgb(239, 239, 239); overflow-wrap: break-word !important;">本文是聊聊架构(ID:archtime)策划的 Re:从 0 开始的微服务架构 专题的第三篇文章,今天我们聊聊内网环境中的 API 开发与治理。</section><section style="max-width: 100%; font-size: 20px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; max-width: 100%; height: 57px; line-height: 62px; color: rgb(0, 179, 138); border-bottom: 2px solid rgb(0, 179, 139); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVI5v3TrVZwLwNC8NRkmOzc2A1wse0EHmTTpa8YU0DUe0hMZlOWhmNI3A/0?wx_fmt=jpeg&quot;); background-position: 50% 50%; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 55px; display: inline-block; overflow-wrap: break-word !important;">写在前面</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">前面的文章中有说到微服务的通信方式,Martin Folwer 先生在他对微服务的定义中也提到“每个服务运行在其独立的进程中,服务与服务间采用 轻量级的通信机制 互相协作(通常是基于 HTTP 协议的 RESTful API)”。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">那么,在各个微服务之间具体怎么进行轻量级的通信呢?这篇文章就来聊聊微服务 API 开发及治理的几个方面。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">首先需要解释一下,标题中的“内网环境中 的 API”指的是提供给内网里的其它微服务调用的 API。与其相对应的是“开放给互联网 用户调用的 API”,它们的开发方法大体相同,但治理方法却不太一样。例如开放给互联网用户调用的 API 需要在 API 网关上加上授权、鉴权、限流、限并发、统计、计费等等功能。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">本篇文章分享的是内网环境中的 API 开发及治理。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">前两篇文章链接:</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5MDE0Mjc4MA==&amp;mid=2650997457&amp;idx=1&amp;sn=c9024d2b47d88f15266d6d15544653ac&amp;chksm=bdbefa828ac973940ecaef2b74efed5f645b6e023756741b4a45f718b3373d565daef1b4d492&amp;scene=21#wechat_redirect" target="_blank" style="color: rgb(87, 107, 149); -webkit-tap-highlight-color: rgba(0, 0, 0, 0); cursor: pointer; max-width: 100%; overflow-wrap: break-word !important;">Re:重识微服务架构</a></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5MDE0Mjc4MA==&amp;mid=2650997370&amp;idx=1&amp;sn=a8aee267775dcad20d61dd9bb630975b&amp;chksm=bdbefa298ac9733fe7fdd79da4eedba6ca48706274bde9f192a47a407cbae731f47ce0cad8ab&amp;scene=21#wechat_redirect" target="_blank" style="color: rgb(87, 107, 149); -webkit-tap-highlight-color: rgba(0, 0, 0, 0); cursor: pointer; max-width: 100%; overflow-wrap: break-word !important;">如何快速搭建一个微服务架构?</a></p><section style="max-width: 100%; font-size: 20px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; max-width: 100%; height: 57px; line-height: 62px; color: rgb(0, 179, 138); border-bottom: 2px solid rgb(0, 179, 139); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVI5v3TrVZwLwNC8NRkmOzc2A1wse0EHmTTpa8YU0DUe0hMZlOWhmNI3A/0?wx_fmt=jpeg&quot;); background-position: 50% 50%; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 55px; display: inline-block; overflow-wrap: break-word !important;">API 开发</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">API 开发,首先考虑的就是该用什么样的协议,是 HTTP API 还是 RPC?</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">我们先来介绍一下这两种 API 类型:</p><section style="margin-top: 30px; margin-left: 8px; max-width: 100%; font-size: 16px; text-align: left; color: rgb(0, 179, 138); overflow-wrap: break-word !important;"><span style="margin-right: 10px; max-width: 100%; display: inline-block; width: 15px; height: 15px; background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIfIHr7HJffDI8C7GXA4amLntr7glT88gB3wFicndpeMzFeJyRlIjZImw/0?wx_fmt=jpeg&quot;); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 100% 100%; overflow-wrap: break-word !important;"></span>&nbsp;HTTP API</section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">HTTP API 指的是简单的基于 HTTP 协议的 API,具体的例子就是 Spring MVC 的 Controller,例如:</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">“http://127.0.0.1/helloworld/myapi.do”。</p><section style="margin-top: 30px; margin-left: 8px; max-width: 100%; font-size: 16px; text-align: left; color: rgb(0, 179, 138); overflow-wrap: break-word !important;"><span style="margin-right: 10px; max-width: 100%; display: inline-block; width: 15px; height: 15px; background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIfIHr7HJffDI8C7GXA4amLntr7glT88gB3wFicndpeMzFeJyRlIjZImw/0?wx_fmt=jpeg&quot;); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 100% 100%; overflow-wrap: break-word !important;"></span>&nbsp;RPC</section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">RPC 就是 Remote Procedure Call,中文名远程过程调用,在 API 调用的场景下,大多指的是基于 Socket 通信方法的远程调用(当然,我们也可以使用 HTTP 协议来实现 RPC 调用,例如 gRPC)。Json-RPC 和 Xml-RPC 指的是使用 Json 或 Xml 作为文本格式的方式传输命令和数据。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">那么回到刚才那个问题,到底要使用 HTTP API 还是 RPC 呢?我们之所要对比 HTTP API 和 RPC,主要是因为大家都知道 HTTP 简单,而基于 Socket 的 RPC 性能更好。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">这个问题我们纠结了很久,直到后来,想明白了下面两件事,最终决定在绝大部分场景中使用 HTTP API。</p><section style="max-width: 100%; font-size: 16px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; padding-left: 30px; max-width: 100%; display: inline-block; height: 45px; line-height: 45px; color: rgb(8, 156, 187); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIhKtLMNp1xlkuMpKiaQcPfQuiapYTOkMLHvdZ4hlricbL8JNF4Qcu2J7Nw/0?wx_fmt=jpeg&quot;); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 45px; overflow-wrap: break-word !important;">HTTP API 的性能足以支撑大多数项目</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">通常来讲(根据资料),算上序列化的时间,RPC 协议的吞吐量是 HTTP 性能 两倍(没有亲测),例如 Protobuf、Thrift、Kyro、Dubbo 等等。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">这里面,又以 Thrift 的性能最高。具体的性能测试报告可以参考《RPC 框架性能基本比较测试》。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175306_h5.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">我们团队在结合自身技术栈、成本、稳定性、易用性、可维护性、业务场景等等因素综合考虑后,觉得我们面临的大多数场景中,HTTP 和 RPC 的性能差别并不是主要问题。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">再加上下图所示的 HTTP 性能测试结果作为佐证,我们完全可以采用 HTTP API 的方式来进行微服务 API 开发。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">再者,当业务发展到一定的程度,如果某些业务功能的性能压力变大时,我们还是可以使用 RPC 小范围地进行改造。这也是符合敏捷思想的一个决定。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">下图是对 helloworld 页面进行 10000 次连续请求的测试结果,总耗时 1.504 秒,平均每个请求耗时 0.15 毫秒。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175349_d4.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><span style="max-width: 100%; color: rgb(136, 136, 136); font-size: 14px; overflow-wrap: break-word !important;">测试环境:原生 Tomcat7(没有任何优化)运行在本地虚拟机上</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">下面是对 helloworld 页面以 100 并发数进行 10 万次请求的测试结果,平均每个请求耗时 11.9 毫秒。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175429_eq.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><span style="max-width: 100%; color: rgb(136, 136, 136); font-size: 14px; overflow-wrap: break-word !important;">测试环境:原生 Tomcat7(没有任何优化)运行在本地虚拟机上</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">所以,按照上面的测试结果,HTTP API 方式的性能完全足以支撑绝大多数的微服务 API 开发。让我们把 RPC 方式留给那些可能出现双十一业务量的大型互联网公司去玩。</p><section style="max-width: 100%; font-size: 16px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; padding-left: 30px; max-width: 100%; display: inline-block; height: 45px; line-height: 45px; color: rgb(8, 156, 187); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIhKtLMNp1xlkuMpKiaQcPfQuiapYTOkMLHvdZ4hlricbL8JNF4Qcu2J7Nw/0?wx_fmt=jpeg&quot;); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 45px; overflow-wrap: break-word !important;">RESTful API 适用于开放 API 的场景</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">这是另一个折磨人的问题。相对于 HTTP API,RESTful API 在 HTTP API 的基础上增加了一些非常抽象晦涩的概念,例如资源(Resource)、表述(REpresentation)、状态转移(State Transfer)、统一接口(Uniform Interface)……。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">在经历了一次又一次的折磨,例如“login/logout 是什么 RESTful 方法?”、“批量删除该怎么实现?”、“RESTful 的 resource 究竟该怎么定义?”之后,越来越感觉这是一个形而上学的问题,太过于抽像。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">我们不该盲从于时髦的技术,需要加上技术人的基于自身情况的理性思考。所以,RESTful 虽好,但不是我们团队的菜。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">再者,即使团队中有些人可以理解并正确地实践,也很难或者说不可能让整个团队来正确地实践这样一种方法。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">所以,我们在一番挣扎后,选择了 HTTP API 方式,原来怎么开发,现在还是怎么开发,把主要精力放到了 API 的监控和治理上面。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">这里推荐大家看看知乎上的这篇讨论 《WEB 开发中,使用 JSON-RPC 好,还是 RESTful API 好?》,几位大神讲得都挺好。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">https://www.zhihu.com/question/28570307</p><section style="max-width: 100%; font-size: 20px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; max-width: 100%; height: 57px; line-height: 62px; color: rgb(0, 179, 138); border-bottom: 2px solid rgb(0, 179, 139); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVI5v3TrVZwLwNC8NRkmOzc2A1wse0EHmTTpa8YU0DUe0hMZlOWhmNI3A/0?wx_fmt=jpeg&quot;); background-position: 50% 50%; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 55px; display: inline-block; overflow-wrap: break-word !important;">API 治理</span></section><section style="max-width: 100%; font-size: 16px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; padding-left: 30px; max-width: 100%; display: inline-block; height: 45px; line-height: 45px; color: rgb(8, 156, 187); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIhKtLMNp1xlkuMpKiaQcPfQuiapYTOkMLHvdZ4hlricbL8JNF4Qcu2J7Nw/0?wx_fmt=jpeg&quot;); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 45px; overflow-wrap: break-word !important;">API 文档</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">API 存在的意义在于有人调用它,如果调用方在调用 API 的时候很麻烦,甚至不能正确地调用,那么团队内部及团队之间的沟通成本及配合程度就会大受影响。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">我们是通过文档来沟通的,项目开始的时候还好,但随着时间的推移,文档的更新变得不是那么及时(这其实是个自我辩解的说法,事实是大部分情况下文档都不更新了),API 变更时,也不容易找出哪些模块调用了这个 API。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">所以,得先解决 文档不及时更新 的问题。虽然我们可以通过流程管理的方式来强制大家更新文档,但这对于开发人员来说,显然是不够科学或人性化的,因为变更一个 API,就要在两个地方进行修改,一是 API 代码,二是 API 文档,程序员的思维就得在代码和文档之间不断切换,工作效率必然受影响。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">我们就想,能不能只需要在同一个地方修改,如果能做到,API 文档的更新就没有那么麻烦了,于人于已都是好事。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">经过调研,我们选择使用 Swagger 来编写文档,按照 Swagger 的规范,在 API 上加一些描述性的 Annotation 就可以了。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175517_zh.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">通过以上的 Annotation,将自动生成以下在线 API 文档。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175553_hv.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">调用方可以在 API 文档界面填入参数并点击“Try it out!”按钮尝试调用这个 API。这样,在没有 API 提供方支持的情况下,即可以自行完成绝大部分的 API 调用,是不是很爽?</p><section style="max-width: 100%; font-size: 16px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; padding-left: 30px; max-width: 100%; display: inline-block; height: 45px; line-height: 45px; color: rgb(8, 156, 187); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIhKtLMNp1xlkuMpKiaQcPfQuiapYTOkMLHvdZ4hlricbL8JNF4Qcu2J7Nw/0?wx_fmt=jpeg&quot;); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 45px; overflow-wrap: break-word !important;">调用链管理</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">API 开发出来了,API 文档也写好了,接下来就是被调用了。前篇文章讲到,通过 Spring Cloud 的 Eureka + Ribbon + Zuul 可以很方便地调用到这些 API。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">那么,如何来追踪 API 被谁调用了,调用是否出错及出错原因,调用链路里各个 API 的性能怎么样,是不是存在僵尸 API……这些都是关于 API 治理的问题。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">实现这个目标,有一个比较取巧的方法,就是在 Ribbon 的客户端里做点文章,在调用 API 之前记录一下开始时间,API 调用返回后,记录 API 调用耗时、调用状态,如果有错则记录一下错误原因。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">如果还想追踪调用链,可以在请求头里加上一个调用链 ID,这样就来把调用关系都串连起来。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">下边是我们自己研发的调用链管理组件(DCTrace)的几个效果图:</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175651_x8.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><span style="max-width: 100%; color: rgb(136, 136, 136); font-size: 14px; overflow-wrap: break-word !important;">查看微服务之间的调用关系,调用性能</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175707_tg.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><span style="max-width: 100%; color: rgb(136, 136, 136); font-size: 14px; overflow-wrap: break-word !important;">查看调用失败原因</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175741_lf.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><span style="max-width: 100%; color: rgb(136, 136, 136); font-size: 14px; overflow-wrap: break-word !important;">图形化查看调用关系,太乱 ,下次迭代改进一下 [摊手]</span></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">站在技术管理者的角度,可以从调用链里看出来,哪些模块之间发生了不正当关系 [噗嗤];哪些模块之间本该有关系的,事实却没有;通过对比 Swagger 和调用链的 API 清单,找出僵尸 API……</p><section style="max-width: 100%; font-size: 16px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; padding-left: 30px; max-width: 100%; display: inline-block; height: 45px; line-height: 45px; color: rgb(8, 156, 187); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVIhKtLMNp1xlkuMpKiaQcPfQuiapYTOkMLHvdZ4hlricbL8JNF4Qcu2J7Nw/0?wx_fmt=jpeg&quot;); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 45px; overflow-wrap: break-word !important;">API 测试</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">使用微服务架构后,API 是每个微服务的 唯一能力出口。由于互联网行业的快速发展,软件需求变更变得越来越频繁,迭代升级的速度变得越来越快。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">对于提供方来说,需要保证变更和迭代的过程中,不影响之前承诺的功能(包括正确性、稳定性和性能等)。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">对于调用方来说,同样需要确保自身依赖的 API 能正常使用,不能因为其它模块的错误而导致自身业务受到影响(包括正确性、稳定性和性能等)。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">毕竟,从组织角度来看,系统出错就是出错,不管原因是自身导致的还是服务提供方导致的,所以 服务调用方就需要对服务提供方进行管理。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">这也就是前几年契约测试(Pact)方法大行其道的原因。有兴趣的朋友可以去看看这种测试方法。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">对于 API 白盒测试,推荐使用基于 Java 的 REST-Assured 测试框架,用起来特别方便。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">https://github.com/rest-assured/rest-assured</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175833_mv.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">更进一步,基于 HTTP 协议、JSON/XML 报文的规范性,完全可以开发一个 API 测试小工具(暂且叫它 小鹰 吧)来替换 REST-Assured。我们也暂未实践,只是觉得会很有用,供大家参考。</p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;"><img src="https://51techud.yykj.com:9002/forumpic/20210818175926_lv.webp" style="max-width:100%;"><br></p><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">基础步骤是:</p><ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 2.2em; max-width: 100%; overflow-wrap: break-word !important;"><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">服务提供方开发 API,并正确书写 Swagger 文档。</p></li><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">服务提供方在小鹰的界面上选择需要测试的 API,并填写测试参数。(API 清单和参数都可以通过调用 Swagger 的 API 获取)</p></li><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">服务调用方根据自已的理解,也将对自己有用的服务方提供的 API 配置到小鹰上。</p></li><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">小鹰 7*24 小时为服务提供方和调用方巡视这些 API,并在异常出现时发送警报。</p></li></ol><section style="max-width: 100%; font-size: 20px; overflow-wrap: break-word !important;"><span style="margin-top: 38px; margin-bottom: 10px; max-width: 100%; height: 57px; line-height: 62px; color: rgb(0, 179, 138); border-bottom: 2px solid rgb(0, 179, 139); background-image: url(&quot;http://mmbiz.qpic.cn/mmbiz_jpg/YriaiaJPb26VNlnpGia1pT5OLoa38raPgVI5v3TrVZwLwNC8NRkmOzc2A1wse0EHmTTpa8YU0DUe0hMZlOWhmNI3A/0?wx_fmt=jpeg&quot;); background-position: 50% 50%; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 55px; display: inline-block; overflow-wrap: break-word !important;">写在最后</span></section><p style="margin-top: 0px; margin-bottom: 0px; padding-top: 23px; padding-right: 8px; padding-left: 8px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">所以,对于微服务 API 开发,我们</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; padding-left: 2.2em; max-width: 100%; overflow-wrap: break-word !important;"><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">使用最常见的技术(例如 Spring MVC)进行 API 开发</p></li><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">使用 REST-Assured(以及未来的 小鹰)进行测试</p></li><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">使用 Swagger 来管理 API 文档</p></li><li style="max-width: 100%; overflow-wrap: break-word !important;"><p style="margin-top: 0px; margin-bottom: 0px; max-width: 100%; clear: both; min-height: 1em; font-size: 16px; text-align: justify; white-space: pre-line; line-height: 27px; color: rgb(74, 74, 74); overflow-wrap: break-word !important;">使用自研的 DCTrace 进行调用链管理</p></li></ul><section style="max-width: 100%; font-size: 20px; overflow-wrap: break-word !important;"><br></section></section></div></div></div></div><div id="js_pc_qr_code" style="position: fixed; left: 0px; right: 0px; top: 32px; color: rgb(113, 115, 117); text-align: center; font-family: -apple-system, BlinkMacSystemFont, &quot;Helvetica Neue&quot;, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei UI&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif; font-size: 16px; letter-spacing: 0.544px; background-color: rgb(237, 237, 237);"><div style="margin-right: auto; margin-left: auto; position: relative; width: 740px;"><div style="padding: 16px; position: absolute; right: -140px; top: 0px; width: 140px; border: 1px solid rgb(217, 218, 220); background-color: rgb(255, 255, 255); overflow-wrap: break-word; hyphens: auto;"><img id="js_pc_qr_code_img" src="https://mp.weixin.qq.com/mp/qrcode?scene=10000004&amp;size=102&amp;__biz=MjM5MDE0Mjc4MA==&amp;mid=2650997665&amp;idx=1&amp;sn=18b38f992c7b430d7f8d9683a53bca3f&amp;send_time=" style="width: 102px; height: 102px;"><p style="margin-top: 0px; margin-bottom: 0px; font-size: 14px; line-height: 20px;">微信扫一扫<br>关注该公众号</p></div></div></div>
赞(0) 收藏(0)  分享
相关标签: API,RESTful API
0个回复
  • 消灭零回复
Vaptcha启动中...