CQRS架构中命令模型返回201响应时使用查询模型资源URL是否合规?
这个设计不符合CQRS的设计原则和REST接口语义,是不合理的。同时命令模型不应该知晓查询模型的URL规则,命令侧控制器也绝对不应该和查询模型产生耦合,原因如下:
- 首先违背了CQRS读写隔离的核心初衷
命令模型的唯一职责是处理写请求、校验业务规则、落地写操作、发布领域事件,不需要关心上层查询的任何实现逻辑,包括查询侧的路由规则、数据结构、入口规则。如果命令侧需要硬编码查询侧的/subscription/news路径,后续只要查询侧调整路由(比如改成/feeds/news),命令侧的代码也要同步修改,等于完全白做了读写拆分,两边又绑死在了一起。 - 示例的响应不符合REST语义规范
201 Created状态码对应的Location响应头,要求必须指向本次请求刚刚创建的单条资源的直接访问地址,而不是一个资源集合入口。调用方提交创建文章的请求之后,拿到的Location是新闻集合列表,根本无法直接定位到自己刚创建的内容,完全不符合接口语义约定。 - 适配当前场景的两个优化方案:
- 如果你现在是同事务强一致的读写实现,命令侧创建资源完成后直接返回资源唯一ID即可,前端拿到ID后自行拼接查询侧的资源地址拉取数据,完全不需要命令侧感知查询侧的URL规则。比如
POST /articles返回201,响应体携带"article_id": "xxx",前端自行请求/subscription/news/xxx获取数据。 - 如果后续你打算把读写改成最终一致(把同事务更新查询模型改成异步事件消费),可以把创建接口的响应改成202 Accepted,前端通过轮询或者推送通知获取创建结果,两边完全没有任何耦合。
- 如果你现在是同事务强一致的读写实现,命令侧创建资源完成后直接返回资源唯一ID即可,前端拿到ID后自行拼接查询侧的资源地址拉取数据,完全不需要命令侧感知查询侧的URL规则。比如
最后再明确下耦合问题的边界:命令侧的任何代码都不要依赖查询侧的配置、逻辑、结构,否则后续你要做读写服务拆分、独立扩容、查询逻辑重构的时候,都会被这层不必要的依赖卡住。
内容的提问来源于stack exchange,提问作者chytonpide
相关产品推荐
相关产品推荐

