尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Apollo Http 接口客户端接入指南:为 Java/.Net 之外的语言实现配置读取

Apollo Http 接口客户端接入指南:为 Java/.Net 之外的语言实现配置读取 Apollo Http 接口客户端接入指南为 Java/.Net 之外的语言实现配置读取【免费下载链接】apolloApollo is a reliable configuration management system suitable for microservice configuration management scenarios.项目地址: https://gitcode.com/gh_mirrors/apoll/apolloApollo 配置中心官方维护的客户端目前仅有 Java 与 .Net 两种其他语言Go、Python、NodeJS、PHP、C/C、Rust 等的应用可通过本文介绍的纯 Http 接口直接接入 Apollo 读取配置、感知配置更新并支持灰度发布与访问密钥鉴权。读完本文你将掌握 Apollo 配置服务的三个核心接口带缓存读取、不带缓存读取、long polling 推送通知的 URL 格式、参数语义、返回格式与错误码约定并能在任意语言中独立实现一个可靠、支持实时更新的 Apollo 客户端。本文同时结合本仓库中apollo-configservice模块的控制器与过滤器源码解释每个接口在服务端的真实处理逻辑方便第三方客户端开发者对照实现。社区中已有热心用户贡献了 Go、Python、NodeJS、PHP、C 的客户端其使用说明可分别参考 docs/zh/client 目录下的 golang-sdks-user-guide.md、python-sdks-user-guide.md、nodejs-sdks-user-guide.md、php-sdks-user-guide.md、c-sdks-user-guide.md 等文档。一、应用接入 Apollo在使用任何 Http 接口之前需要先在 Apollo 中接入你的应用创建 App 并获取appId具体步骤可以参考应用接入文档。接入完成后你还需要在 Portal 中为应用添加 Namespace、配置项并执行发布操作Http 接口返回的配置内容即来自这些已发布的配置。二、通过带缓存的 Http 接口从 Apollo 读取配置/configfiles/json该接口会从配置服务的本地缓存中获取配置适合频率较高的配置拉取请求如简单的每 30 秒轮询一次配置。由于缓存最多会有一秒的延时所以如果需要配合配置推送通知实现实时更新配置的话请参考下一节的「不带缓存的 Http 接口」以及「配置更新推送」章节。2.1 接口说明URL{config_server_url}/configfiles/json/{appId}/{clusterName}/{namespaceName}?ip{clientIp}MethodGET参数说明参数名是否必须参数值备注config_server_url是Apollo配置服务的地址即 Config Serviceconfigservice的对外地址与 Java 客户端中配置的apollo.meta解析后的服务地址一致appId是应用的appId接入 Apollo 时申请的应用标识clusterName是集群名一般情况下传入default即可。如果希望配置按集群划分可以参考集群独立配置说明做相关配置然后在这里填入对应的集群名。namespaceName是Namespace的名字如果没有新建过 Namespace 的话传入application即可。如果创建了 Namespace并且需要使用该 Namespace 的配置则传入对应的 Namespace 名字。需要注意的是对于 properties 类型的 namespace只需要传入 namespace 的名字即可如application对于其它类型的 namespace需要传入 namespace 的名字加上后缀名如datasources.jsonip否应用部署的机器ip这个参数是可选的用来实现灰度发布服务端会据此匹配灰度规则并返回对应灰度集群的配置。如果不想传这个参数请注意 URL 中从?号开始的 query parameters 整个都不要出现。2.2 接口返回格式该 Http 接口返回的是 JSON 格式、UTF-8 编码包含了对应 namespace 中所有的配置项。若是 properties 类型的 namespace返回内容 Sample 如下{ portal.elastic.document.type:biz, portal.elastic.cluster.name:hermes-es-fws }若不是 properties 类型的 namespace返回内容 Sample 如下content字段是 namespace 的内容{ content: {\portal.elastic.document.type\:\biz\,\portal.elastic.cluster.name\:\hermes-es-fws\} }此外/configfiles还有两种输出格式变体通过{config_server_url}/configfiles/raw/{appId}/{clusterName}/{namespaceName}?ip{clientIp}可以获取到原始的配置内容不会进行转义例如 JSON 格式的 namespace 会原样返回其中的 JSON 文本通过{config_server_url}/configfiles/{appId}/{clusterName}/{namespaceName}?ip{clientIp}可以获取到properties 形式的配置Content-Type为text/plain;charsetUTF-8。2.3 服务端实现缓存如何工作该接口由 ConfigFileController.java 实现对应RequestMapping(/configfiles)源码位置。从源码看它的「带缓存」体现在以下几点本地 Guava CachelocalCache采用expireAfterWrite(30, MINUTES)的 30 分钟写入过期策略并以maximumWeight(50MB)限制总缓存大小源码位置发布即失效控制器实现了ReleaseMessageListener接口当有新的 ReleaseMessage即配置被发布到达时handleMessage会按 watch key 精确失效对应的缓存条目源码位置这就是「最多有一秒延时」的原因灰度隔离queryConfig在处理前会先通过grayReleaseRulesHolder.hasGrayReleaseRule(appId, clientIp, clientLabel, namespace)判断当前请求是否命中灰度规则命中则直接绕过缓存从数据库加载避免灰度配置污染公共缓存源码位置。三个输出格式properties/json/raw最终都复用了configController.queryConfig(...)的核心加载逻辑只是对返回结果做了不同的序列化loadConfig方法源码位置。2.4 测试由于是 Http 接口所以在 URL 组装 OK 之后直接通过浏览器、或者相关的 http 接口测试工具curl、Postman 等访问即可。例如curl http://{config_server_url}/configfiles/json/100004458/default/application三、通过不带缓存的 Http 接口从 Apollo 读取配置/configs该接口会直接从数据库中获取配置并提供灰度、公共 namespace 合并等完整能力可以配合配置推送通知实现实时更新配置。3.1 接口说明URL{config_server_url}/configs/{appId}/{clusterName}/{namespaceName}?releaseKey{releaseKey}messages{messages}label{label}ip{clientIp}MethodGET参数说明参数名是否必须参数值备注config_server_url是Apollo配置服务的地址即 Config Service 的对外地址appId是应用的appId接入 Apollo 时申请的应用标识clusterName是集群名一般情况下传入default即可。如果希望配置按集群划分可以参考集群独立配置说明做相关配置然后在这里填入对应的集群名。namespaceName是Namespace的名字如果没有新建过 Namespace 的话传入application即可。如果创建了 Namespace并且需要使用该 Namespace 的配置则传入对应的 Namespace 名字。需要注意的是对于 properties 类型的 namespace只需要传入 namespace 的名字即可如application对于其它类型的 namespace需要传入 namespace 的名字加上后缀名如datasources.jsonreleaseKey否上一次的releaseKey将上一次返回对象中的releaseKey传入即可用来给服务端比较版本。如果版本比下来没有变化则服务端直接返回 304 以节省流量和运算messages否最新的 notificationId用于给服务端即时更新内存缓存。如果传递了releaseKey而不传递messages参数在服务端多实例、且开启内存缓存时有概率会获取不到最新的配置。这个参数是 json 结构的字符串{details:{key:notificationId}}需要将appId、clusterName、namespaceName使用号拼接为 key。假设现在appIdapp、clusterNamedefault、namespaceNametest、notificationId11则 messages 参数为{details:{appdefaulttest:11}}。使用 messages 参数时需要进行 URL 编码。label否灰度配置的标签这个参数是可选的用于灰度发布的标签规则匹配。ip否应用部署的机器ip这个参数是可选的用于灰度发布的 ip 规则匹配。3.2 接口返回格式该 Http 接口返回的是 JSON 格式、UTF-8 编码。如果配置没有变化传入的releaseKey和服务端的相等则返回HttpStatus 304response body 为空如果配置有变化则会返回HttpStatus 200response body 为对应 namespace 的 meta 信息以及其中所有的配置项。返回内容 Sample 如下{ appId: 100004458, cluster: default, namespaceName: application, configurations: { portal.elastic.document.type:biz, portal.elastic.cluster.name:hermes-es-fws }, releaseKey: 20170430092936-dee2d58e74515ff3 }3.3 服务端实现参数如何生效该接口由 ConfigController.java 实现对应RequestMapping(/configs)源码位置。queryConfig方法的处理流程与各参数一一对应namespace 归一化服务端会先filterNamespaceName去掉.properties后缀再normalizeNamespace修正大小写问题如FX.apollo与fx.apollo视为同一个 namespace源码位置404 语义如果应用自身 namespace 与公共 namespace 都找不到对应的已发布 Release服务端会返回404并记录Apollo.Config.NotFound事件源码位置304 语义服务端将当前所有生效 Release 的releaseKey用连接为latestMergedReleaseKey与客户端传入的releaseKey相等时直接返回 304源码位置公共 namespace 合并当 namespace 不属于当前 appId 时会通过findPublicConfig找到公共 namespace 的所属应用并加载其配置与应用自身配置一起合并返回源码位置增量同步新版本还支持基于releaseKey的增量同步——如果服务端开启了apollo.config-service.incremental-change.enabled会对比客户端与服务端的 Release 历史在响应中附加configurationChanges变更明细源码位置。3.4 测试由于是 Http 接口所以在 URL 组装 OK 之后直接通过浏览器、或者相关的 http 接口测试工具访问即可curl http://{config_server_url}/configs/100004458/default/application四、应用感知配置更新Http long polling 推送通知Apollo 提供了基于 Http long polling 的配置更新推送通知第三方客户端可以看自己实际的需求决定是否需要使用这个功能。如果对配置更新时间不是那么敏感的话可以通过定时刷新来感知配置更新刷新频率可以视应用自身情况来定建议在 30 秒以上配合带缓存的/configfiles/json接口即可如果需要做到**实时感知配置更新1 秒**的话可以参考下面的文档实现配置更新推送功能。4.1 配置更新推送实现思路这里建议大家可以参考 Apollo 的 Java 官方实现apollo-java 仓库中的RemoteConfigLongPollService.java代码量 200 多行总体上还是比较简单的。其核心思路分「初始化」与「请求服务」两步4.1.1 初始化首先需要确定哪些 namespace 需要配置更新推送。Apollo 的实现方式是程序第一次获取某个 namespace 的配置时就会来注册一下这样服务端/客户端就知道有哪些 namespace 需要配置更新推送了。初始化后的结果就是得到一个notifications的 Map内容是namespaceName - notificationId初始值为-1。运行过程中如果发现有新的 namespace 需要配置更新推送直接塞到notifications这个 Map 里面即可。4.1.2 请求服务有了notifications这个 Map 之后就可以请求服务了。请求服务的完整逻辑如下具体的 URL 参数和说明参见后面的接口说明请求远端服务带上自己的应用信息以及notifications信息服务端针对传过来的每一个 namespace 和对应的notificationId检查notificationId是否是最新的如果都是最新的则保持住请求 60 秒如果 60 秒内没有配置变化则返回 HttpStatus 304如果 60 秒内有配置变化则返回对应 namespace 的最新notificationIdHttpStatus 200如果传过来的notifications信息中发现有notificationId比服务端老则直接返回对应 namespace 的最新notificationIdHttpStatus 200客户端拿到服务端返回后判断返回的 HttpStatus如果返回的 HttpStatus 是 304说明配置没有变化重新执行第 1 步如果返回的 HttpStatus 是 200说明配置有变化针对变化的 namespace 重新去服务端拉取配置参见不带缓存的 Http 接口同时更新notificationsMap 中的notificationId重新执行第 1 步。4.2 接口说明URL{config_server_url}/notifications/v2?appId{appId}cluster{clusterName}notifications{notifications}MethodGET参数说明参数名是否必须参数值备注config_server_url是Apollo配置服务的地址即 Config Service 的对外地址appId是应用的appId接入 Apollo 时申请的应用标识clusterName是集群名一般情况下传入default即可。如果希望配置按集群划分可以参考集群独立配置说明做相关配置然后在这里填入对应的集群名。notifications是notifications信息传入本地的notifications信息注意这里需要以 array 形式转为 json 传入如[{namespaceName: application, notificationId: 100}, {namespaceName: FX.apollo, notificationId: 200}]。需要注意的是对于 properties 类型的 namespace只需要传入 namespace 的名字即可如application对于其它类型的 namespace需要传入 namespace 的名字加上后缀名如datasources.json注 1由于服务端会 hold 住请求 60 秒所以请确保客户端访问服务端的超时时间要大于 60 秒。注 2别忘了对参数进行URL encode百分号编码。4.3 接口返回格式该 Http 接口返回的是 JSON 格式、UTF-8 编码包含了有变化的 namespace 和最新的notificationId。返回内容 Sample 如下[ { namespaceName: application, notificationId: 101 } ]4.4 服务端实现long polling 如何 hold 住连接该接口由 NotificationControllerV2.java 实现对应RequestMapping(/notifications/v2)源码位置。第三方客户端在实现时可以对照以下服务端行为做校验异步长连接pollNotification返回的是DeferredResult服务端通过DeferredResultWrapper注册本次请求hold 的时长由bizConfig.longPollingTimeoutInMilli()决定文档约定为 60 秒到达超时时间后返回 304有变更则立刻返回最新notificationId源码位置发布事件驱动handleMessage收到配置发布消息APOLLO_RELEASE_TOPIC后会主动把结果推给所有等待中的DeferredResultWrapper当同时等待的客户端数量超过releaseMessageNotificationBatch配置时会转为异步分批通知避免惊群源码位置参数校验notifications参数无法解析或过滤后为空时服务端会抛出 400 错误invalidNotificationsFormat源码位置。仓库中还提供了该接口的完整集成测试 NotificationControllerV2IntegrationTest.java涵盖 304 超时返回、200 有变更返回、namespace 大小写归一化等场景第三方客户端可以直接把它当作行为契约来对齐。4.5 测试由于是 Http 接口所以在 URL 组装 OK 之后直接通过浏览器、或者相关的 http 接口测试工具访问即可。首次调用时传入notificationId-1即可让服务端立刻返回当前最新版本例如curl http://{config_server_url}/notifications/v2?appId100004458clusterdefaultnotifications%5B%7B%22namespaceName%22%3A%22application%22%2C%22notificationId%22%3A-1%7D%5D五、配置访问密钥签名鉴权Apollo 从1.6.0版本开始增加访问密钥机制从而只有经过身份验证的客户端才能访问敏感配置。如果应用开启了访问密钥客户端发出请求时需要增加签名否则无法获取配置服务端返回 401。需要设置的 Header 信息HeaderValue备注AuthorizationApollo ${appId}:${signature}appId应用的 appIdsignature使用访问密钥对当前时间毫秒值以及所访问的 URL 里的 path 和 query 部分加签后的值具体实现可参考apollo-core中的Signature.signature方法本仓库的调用点见下文Timestamp从1970-1-1 00:00:00 UTC0到现在所经过的毫秒数即System.currentTimeMillis()的返回值5.1 服务端如何校验签名配置服务的访问密钥校验由过滤器 ClientAuthenticationFilter.java 完成第三方客户端实现签名时需注意Timestamp 时效校验服务端要求Timestamp与当前时间的差值小于accessKeyAuthTimeDiffTolerance默认 1 分钟超时返回 401RequestTimeTooSkewed源码位置。这意味着客户端每次请求都必须使用当前时间生成签名不能复用旧签名签名内容仓库中的 AccessKeyUtil.buildSignature 会将请求的path与query如/configs/appId/default/application?ip1.2.3.4拼接连同timestamp一起调用 apollo-core 依赖中的Signature.signature(timestampString, pathWithQuery, secret)计算签名——也就是说path 和 query 的任何变化都会导致签名失效客户端必须用与请求完全一致的 URL 参与加签Authorization 格式服务端按冒号:切分Authorization头取冒号后部分与本地计算签名比对任一可用的密钥secret匹配即通过源码位置。六、错误码说明正常情况下接口返回的 Http 状态码是 200。下面列举了 Apollo 会返回的非 200 错误码说明第三方客户端应据此做好错误处理与日志输出6.1 400 - Bad Request客户端传入参数的错误如必选参数没有传入等客户端需要根据提示信息检查对应的参数是否正确。6.2 401 - Unauthorized客户端未授权如服务端配置了访问密钥客户端未配置或配置错误包括签名不匹配、Timestamp 超时等。6.3 404 - Not Found接口要访问的资源不存在一般是 URL 或 URL 的参数错误或者是对应的 namespace 还没有发布过配置。6.4 405 - Method Not Allowed接口访问的 Method 不正确比如应该使用 GET 的接口使用了 POST 访问等客户端需要检查接口访问方式是否正确。6.5 500 - Internal Server Error其它类型的错误默认都会返回 500对这类错误如果应用无法根据提示信息找到原因的话可以尝试查看服务端日志来排查问题。七、第三方客户端实现要点小结综合以上接口约定与服务端源码实现一个非 Java/.Net 语言的 Apollo 客户端时建议遵循以下要点配置拉取低频场景直接使用/configfiles/json带缓存轮询即可轮询间隔建议 30 秒以上需要实时更新的场景先用/configs全量拉取并记录releaseKey再通过/notifications/v2long polling 订阅变更收到 200 后重新拉取对应 namespace 的配置协议细节long polling 请求的客户端超时必须大于服务端 hold 时长60 秒所有 query 参数都要做 URL encodeproperties 类型 namespace 不带后缀其他类型 namespace 需带后缀如.json、.yml大小写不敏感服务端会归一化版本协商携带上一次的releaseKey与messages{details:{appIdclusternamespace:notificationId}}可避免服务端多实例内存缓存带来的不一致并让服务端返回 304 以节省流量灰度与鉴权需要灰度时传入ip/label参数应用开启访问密钥后所有请求都必须携带Timestamp与Authorization签名头且签名要基于与请求完全一致的 pathquery 生成错误处理按上文错误码表区分 400/401/404/405/500特别是 404 通常表示 namespace 尚未发布配置客户端应视为「暂无配置」而非致命错误。【免费下载链接】apolloApollo is a reliable configuration management system suitable for microservice configuration management scenarios.项目地址: https://gitcode.com/gh_mirrors/apoll/apollo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表