文档 / 搜索 / LingCode Cloud / 远程配置
📘 参考 ● 指南 更新于 2026-06-11

远程配置与实验

一句话:远程配置让你无需发布新版本就能改变应用的行为——功能开关、可调参数,以及在运行时从后端下发的 A/B 实验变体。你在应用里用 lingcode.config 读取这些值;在服务端翻转它们。永远给 get() 传一个默认值,这样配置加载之前应用也能正常工作。

发布版本是一种缓慢、要么全有要么全无的决策方式。把 new_checkout = true 写死,就等于对所有用户一锤定音,唯一的退路是再走一次应用商店发版。远程配置把这件事倒过来:决策放在服务器上,应用在启动时读取它,于是你可以把一个开关往前推进、回拨一档,或者把流量拆进实验变体——这一切都不必动用户手里已经装好的那个二进制包。

为什么要用远程配置

三种活儿,一套机制。功能开关把某条代码路径打开或关闭(先暗发上线、之后再启用、出问题时立刻干掉一处回归)。可调参数暴露一个数字或一段文案,让你不用发版就能调整——一个分页大小、一个价格展示字符串、一个重试次数。实验把不同的变体发给不同的用户,让你测出哪一个胜出。这三者都不过是你的应用在运行时读取的键值对。

要记在脑子里的那条分界:你在客户端读取值,在后端设置值。客户端从不决定一个开关该是什么——它只是发问、拿到答案、然后分支。改变那个答案是一次服务端操作,会在下一次配置加载时生效,完全不涉及重新构建。

SDK 接口

一切都在 client.config 之下(在 /try 和 Mac 预览里,客户端已经被预先注入为 lingcode):

读取一个开关

等配置加载完成,用一个合理的默认值读取开关,然后分支:

await lingcode.config.ready;

const showNewCheckout = lingcode.config.get('new_checkout', false); // 默认 false

if (showNewCheckout) {
  renderNewCheckout();
} else {
  renderOldCheckout();
}

默认值不是摆设——它是配置还没加载、或者请求失败时应用所采用的那个值。挑一个本身就正确的默认值(这里是已有的结账流程),那么无论网络发生什么,你的应用都能优雅降级。

跑一个实验

实验就是一个有两个以上结果的开关:后端为每个客户端分配一个变体,你用 get() 读取它并据此分支。把它和数据分析配对——在你关心的那个结果上调用 logEvent——这样你才能测出哪个变体真正胜出:

await lingcode.config.ready;

const variant = lingcode.config.get('checkout_button', 'control'); // 'control' | 'green' | 'urgent'

renderCheckoutButton(variant);

// 之后,当用户完成转化时——把这个结果归因到该变体
async function onPurchase(amount) {
  await lingcode.telemetry.logEvent('purchase', { variant, amount });
}

进来的是同一个客户端分配,出去的是结果事件——整个闭环就是这样。时间一长,数据分析会告诉你 greenurgent 是否击败了 control,你只需在服务端翻转配置,就能把胜者推全量。

一次性读取全部

当你想要完整的已解析集合时——用来填充一个设置界面,或记录某次会话跑在哪份配置下——就用 all()

await lingcode.config.ready;
const cfg = lingcode.config.all(); // { new_checkout: true, checkout_button: 'green', page_size: 50, ... }

配置该用来做什么——又不该做什么

把远程配置当作功能开关、灰度放量、文案微调和可调数值的归宿。它不是放密钥的地方。私有密钥(Stripe secret、第三方 API key)应当放进密钥保险库,并从函数里读取——函数运行在服务端。另外,要靠你的默认值:应用在每个开关都取默认值时都应表现正确,这样一次缓慢或失败的配置加载永远不会变成一个坏掉的应用。

配置值是下发到客户端的。任何使用你应用的人都能读到它们——打开网络面板它们就在那儿。永远不要把任何敏感信息放进配置值里。它用来控制行为,不是用来放密钥。

底层原理(REST)

SDK 从单个端点拉取配置,并按客户端作用域,这样每个客户端都能拿到属于自己的实验分配:

GET https://lingcode.dev/api/cloud/be/<backend-id>/config?client_id=<id>

响应是一个扁平的键值对对象:

{
  "new_checkout": true,
  "checkout_button": "green",
  "page_size": 50
}

如果请求失败,SDK 会抛出一个 config_failed 错误——这正是为什么每次 get() 调用都该带一个默认值。应用会继续跑在它的默认值上;你不必在调用处内联处理这个错误。