跳到主要内容
新品云 ERP 正式上线,几分钟开通专属实例

技术分享

一个小而完整的接口:把询盘表单送进 CRM 的设计清单

官网上线时,后端被刻意收窄到只做一件事:把「联系我们」的询盘可靠地送进 CRM。接口小,但"小"不等于"缺"——每条失败路径都要有明确的答案。以下是这个端点的完整设计清单,按请求经过的顺序展开。

处理顺序:每一步都想好拒绝的方式

一次提交从进来到入库,顺序固定、逐层收紧:

  1. 取真实客户端 IP(经反代时从转发头读取,前提是部署侧正确传递);
  2. IP 级限流:超过阈值直接 429,附上重试时机;
  3. 请求体大小与 JSON 校验:超限或解析失败即拒;
  4. 字段白名单校验(下表展开);
  5. 人机验证:服务端校验 Turnstile,动作名绑定到本接口;
  6. 全站级配额:兜住分布式来源的异常峰值;
  7. 幂等判定与建档:唯一约束兜底并发;
  8. 落单号:序列生成可读编号,供商务直接引用;
  9. 通知:落库成功之后异步发送。

顺序本身就是设计:先便宜的后昂贵(限流先于验签)、先拒绝后落库(任何校验失败都不产生数据)、通知永远在成功之后(不会出现"收到通知但库里没有")。

字段白名单:多一个字段就是拒绝

字段 约束 说明
姓名(必填) 长度上限 80
电话(必填) 长度上限 80
公司 长度上限 120
邮箱 正则校验 不通过即拒
留言 长度上限 3000
主题 固定枚举(商务/技术/媒体/求职/其他) 便于 CRM 分流
提交键 UUID 幂等标识
来源页 站内路径正则 归因用
同意勾选 必须为 true 合规

白名单的严格模式——出现清单之外的字段直接拒绝——既是注入面的纵深防御,也让协议变更显式化:前端加了字段而接口没更新时,报错比静默丢弃更早暴露问题。

幂等语义:三条路径,各有答案

客户端为每次填写生成提交键,接口按三种情况给确定的回答:

  • 同键、同内容重试 → 返回同一个单号,幂等,重试绝对安全;
  • 同键、内容不同 → 明确报 409 冲突,而不是默默覆盖;
  • 同键并发双请求 → 由数据库唯一约束兜底——"谁先到"不重要,两者得到一致的结论。

配套一个工程细节:内容哈希用规范化后的文本计算(统一空白与大小写敏感规则),否则"看起来一样"的两次提交会被判成冲突。

配额与验证的分工

限流做两层,用意不同:IP 级拦住单点刷量(20 次/小时是我们对正常商务行为的宽松估计);全站级兜住分布式来源的异常峰值。人机验证补上第三层——三层都不假设对方是恶意,只是让自动化的成本高于收益。

限流计数还有一条我们踩过坑的规则:计数独立提交,不随业务事务回滚——否则业务失败会把已消费的次数"退还",限流形同虚设。计数本身的并发正确性(upsert 冲突与重试)另有专文展开。

落档与隐私:承诺要落到行为

线索落 CRM 时带上来源页、语言与主题标签,方便按渠道复盘。与功能同样重要的是两条"不做":不做二次营销用途、不触发第三方数据增强(在模型层面用标记字段抑制,并有测试断言)。隐私承诺写在政策页是文本,落到代码行为才是承诺。

通知:失败不能反噬主流程

有新询盘时给团队发通知,但通知有两个约束:在落库成功之后才发;发送失败只记录并进入重试队列(有上限,成功即清),绝不影响用户看到的"提交成功"。用户视角的成功只取决于一件事——数据真的进了 CRM。

错误码语义

对外错误码保持可枚举、可解释:400(字段问题,附具体字段)、403(人机验证失败)、409(同键异内容)、429(限流,附重试时机)、5xx(服务端,可重试)。前端按码给文案,不猜。

小结

小接口的完整性,等于"每个失败路径都想过":多字段、超配额、重放、冲突、通知失败、后端不可达。清单不长,但它覆盖的正是线上真实会发生的事情——把失败当成接口的一部分来设计,小接口才配得上"可靠"两个字。

相关产品与 ERP 实践文章在宏斋博客。 宏斋云ERP · Blog

返回列表