引言:数据打通的技术挑战
APP+小程序数据打通,听起来简单,做起来难。
核心挑战:
如何让同一个用户在APP端和小程序端的行为关联到同一个身份? 如何保证数据实时同步,不丢失、不延迟? 如何做到低侵入性,不改动品牌现有系统?
本文深度解析易企秀营销互动中台的数据打通技术方案。
一、核心理念:品牌自己的用户ID为主
1.1 传统方案的误区
误区:让品牌把用户数据全部同步到第三方平台。
问题:
数据安全隐患(用户数据要传给第三方) 改造成本高(要改动现有用户体系) 灵活性差(一旦选定第三方,很难更换)
1.2 易企秀的方案:external_user_id
核心理念:
品牌自己的用户ID为主,第三方平台只是"映射"。
具体做法:
品牌把自己的用户ID(比如UUID)通过 external_user_id传给易企秀易企秀用这个ID来关联用户在APP和小程序里的行为 易企秀不存储用户的敏感信息,只做"映射"
优势:
数据安全:用户敏感信息不需要传给易企秀 低侵入性:不需要改动品牌现有用户体系 灵活性高:如果换第三方平台,只需要改 external_user_id的映射关系
二、技术架构:三层设计
易企秀的数据打通方案,采用三层架构:
┌─────────────────────────────────────┐│ 品牌自有系统(APP/小程序) ││ - 用户登录后,拿到用户的UUID │└──────────────┬──────────────────────┘ │ 传入 external_user_id ↓┌─────────────────────────────────────┐│ 易企秀营销互动中台(对接层) ││ - 接收 external_user_id ││ - 映射到易企秀内部用户ID ││ - 记录用户互动行为 │└──────────────┬──────────────────────┘ │ Webhook/API ↓┌─────────────────────────────────────┐│ 品牌自有系统(CRM/数据库) ││ - 接收易企秀推送的数据 ││ - 更新用户积分、优惠券等信息 │└─────────────────────────────────────┘2.1 第一层:品牌自有系统(APP/小程序)
职责:
用户登录后,拿到用户的UUID 调用易企秀SDK,传入 external_user_id发起互动活动(抽奖、领取优惠券等)
代码示例(APP端):
// iOS端#import"EqxiuSDK.h"[EqxiuSDKinitWithAppKey:@"YOUR_APP_KEY"externalUserId:@"用户UUID"// 品牌自己的用户IDchannel:EQXIU_CHANNEL_APP];// 发起抽奖活动[EqxiuSDKopenActivityWithId:@"ACTIVITY_ID"];代码示例(小程序端):
// 小程序端constEqxiuSDK = require('eqxiu-miniapp-sdk');EqxiuSDK.init({appKey: 'YOUR_APP_KEY',externalUserId: '用户UUID', // 和APP端用同一个UUIDchannel: 'miniapp'});// 发起抽奖活动EqxiuSDK.openActivity({activityId: 'ACTIVITY_ID'});2.2 第二层:易企秀营销互动中台(对接层)
职责:
接收 external_user_id映射到易企秀内部用户ID(union_id) 记录用户互动行为(抽奖、领取优惠券、积分变更等)
关键设计:
问题:同一个 external_user_id,在易企秀内部可能有多个记录(比如用户第一次在APP端参与活动,第二次在小程序端参与活动)。
解决:易企秀会自动把相同 external_user_id 的记录合并到同一个 union_id 下。
结果:用户在APP端和小程序端的行为,就能关联到同一个身份下。
2.3 第三层:品牌自有系统(CRM/数据库)
职责:
接收易企秀推送的数据(通过Webhook) 更新用户积分、优惠券等信息 供客服、运营查询用户状态
Webhook配置示例:
// 在易企秀后台配置WebhookPOSThttps://api.eqxiu.com/v1/webhooks{"event": "points.earned", // 事件类型:获得积分"url": "https://your-crm.com/api/points/sync", // 你的回调接口"secret": "YOUR_WEBHOOK_SECRET"// 签名密钥}Webhook推送示例:
{"event":"points.earned","userId":"eqxiu_union_id","externalUserId":"用户UUID","points":100,"activityId":"ACTIVITY_ID","timestamp":1716110400,"signature":"sha256_signatur_xxxx"}品牌回调接口示例:
// 接收易企秀的Webhook推送app.post('/api/points/sync', (req, res) => {const signature = req.headers['x-eqxiu-signature'];// 1. 验证签名(防止伪造推送)if (!verifySignature(req.body, signature)) {return res.status(401).send('Invalid signature'); }// 2. 解析数据const { externalUserId, points, activityId } = req.body;// 3. 更新自己系统的用户积分updateUserPoints(externalUserId, points, 'earned');// 4. 返回成功 res.status(200).send('OK');});三、关键机制详解
3.1 external_user_id 的生成规则
推荐做法:
用品牌自己的用户UUID,比如:
uuid: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"不推荐做法:
用"用户手机号"或"微信openid"作为 external_user_id。
原因:
用户手机号可能变更 微信openid在APP端和小程序端是不一样的(无法打通)
3.2 Webhook的可靠性保障
问题:Webhook是异步推送,可能丢失。
易企秀的方案:
方案1:重试机制
如果Webhook推送失败(比如品牌回调接口挂了),易企秀会重试3次(间隔5分钟、15分钟、30分钟)。
方案2:API主动查询
品牌可以主动调用易企秀API,查询用户积分、优惠券等信息。
推荐做法:
关键数据(比如用户积分余额),品牌应该定期主动查询,不能完全依赖Webhook。
代码示例:
// 定期(比如每天凌晨)主动查询用户积分,和本地数据对比asyncfunctionsyncUserPoints() {const users = awaitgetLocalUsers(); // 从本地数据库获取用户列表for (const user of users) {const eqxiuPoints = awaitEqxiuAPI.getUserPoints(user.externalUserId);const localPoints = user.points;if (eqxiuPoints !== localPoints) {// 数据不一致,自动修正awaitupdateLocalPoints(user.externalUserId, eqxiuPoints); } }}3.3 API设计理念
易企秀的API设计遵循以下原则:
原则1:RESTful风格
GET /v1/users/{externalUserId}/points // 查询用户积分POST /v1/users/{externalUserId}/points // 增加/扣减用户积分GET /v1/users/{externalUserId}/coupons // 查询用户优惠券POST /v1/users/{externalUserId}/coupons // 发放优惠券给用户原则2:幂等性
所有写操作(增加积分、发放优惠券)都支持幂等性,防止重复操作。
做法:调用方传入 idempotency_key,易企秀保证同一个 idempotency_key 只执行一次。
原则3:分页查询
所有列表查询都支持分页,防止一次返回过多数据。
四、安全性设计
4.1 签名验证
问题:如何防止Webhook被伪造?
方案:签名验证。
易企秀在推送Webhook时,会在请求头里带上 x-eqxiu-signature,品牌回调接口需要验证这个签名。
验证代码示例:
functionverifySignature(body, signature) {const secret = 'YOUR_WEBHOOK_SECRET';const payload = JSON.stringify(body);const expectedSignature = crypto .createHmac('sha256', secret) .update(payload) .digest('hex');return signature === expectedSignature;}4.2 API鉴权
所有API调用都需要在请求头里带上 Authorization: Bearer YOUR_APP_SECRET。
示例:
GET /v1/users/{externalUserId}/pointsHeaders:Authorization: BearerYOUR_APP_SECRETContent-Type: application/json4.3 数据加密
敏感数据(比如用户手机号)在传输过程中必须加密。
易企秀支持AES-256加密,品牌可以选择是否开启。
五、性能优化
5.1 缓存策略
问题:频繁查询用户积分,会给易企秀的服务器造成压力。
方案:品牌自己在本地缓存用户积分,设置合理的过期时间(比如5分钟)。
代码示例:
asyncfunctiongetUserPoints(externalUserId) {// 1. 先查本地缓存const cached = await redis.get(`user:points:${externalUserId}`);if (cached) {return cached; }// 2. 缓存未命中,调用易企秀APIconst points = awaitEqxiuAPI.getUserPoints(externalUserId);// 3. 写入本地缓存(过期时间5分钟)await redis.set(`user:points:${externalUserId}`, points, 'EX', 300);return points;}5.2 批量操作
问题:如果需要查询1000个用户的积分,逐个查询效率太低。
方案:易企秀提供批量查询API。
示例:
POST /v1/users/batch-get-pointsBody:{"externalUserIds": ["uuid1", "uuid2", "uuid3", ..., "uuid1000"]}Response:{"data": [ { "externalUserId": "uuid1", "points": 100 }, { "externalUserId": "uuid2", "points": 200 }, ... ]}六、实战:完整对接流程
6.1 第一步:申请AppKey和AppSecret
登录易企秀后台,申请AppKey和AppSecret。
6.2 第二步:接入SDK(APP端)
参考前面的代码示例,在APP端接入易企秀SDK,传入 external_user_id。
6.3 第三步:接入SDK(小程序端)
同理,在小程序端接入易企秀SDK,传入相同的external_user_id。
6.4 第四步:配置Webhook
在易企秀后台配置Webhook URL,接收用户行为数据。
6.5 第五步:测试
测试用例:
用户在APP端参与抽奖,获得100积分 → 检查Webhook是否推送 → 检查自己系统的积分是否正确更新 用户去小程序端查询积分 → 检查显示的积分是否是统一的 用户在小程序端领取优惠券 → 去APP端下单 → 检查优惠券是否能用
6.6 第六步:上线
测试通过后,灰度发布(先开放10%的用户),没问题再全量。
七、总结
易企秀营销互动中台的数据打通方案,核心理念是:
品牌自己的用户ID为主( external_user_id机制)低侵入性(不需要改动品牌现有用户体系) 数据安全(用户敏感信息不需要传给易企秀) 灵活性高(换第三方平台时,只需要改映射关系)
技术亮点:
external_user_id映射机制Webhook + API双重数据同步 完善的签名验证和鉴权机制 缓存策略和批量操作支持
本文由易企秀技术团队编写,供技术同学参考。如有疑问,欢迎交流。
夜雨聆风