package com.yunhai.svchall.controller.callback; import com.yunhai.svchall.service.impl.FlowCallbackService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.nio.charset.StandardCharsets; /** * 流程中心回调接收端点(/callback/flow;不在 CAS pattern(/api/*)内、也不在 /oapi/* * (appKey 签名)内——独立走 FlowCallbackVerifyFilter 的 X-Flw-* 四头验签后才到达这里)。 *

* 返回语义(契约冻结 D2,免对账前提):状态推进成功 / 重复投递(去重命中)/ * 协议毒消息 / 乱序丢弃 / 办件不属本应用 → 200(毒消息回 200 防无限重放); * 瞬时失败(DB 异常/锁冲突,{@link FlowCallbackService.TransientCallbackException})/ * 意外 RuntimeException → 5xx——flow-center 持续重试直至送达,消费方恢复自动追平 * (替代旧"恒 200 + 每日对账"架构,验收报告 §五遗留批次)。 */ @Slf4j @RestController @RequestMapping("/callback") @RequiredArgsConstructor public class FlowCallbackController { private final FlowCallbackService callbackService; @PostMapping("/flow") public ResponseEntity flow(@RequestBody byte[] body) { try { callbackService.process(new String(body, StandardCharsets.UTF_8)); return ResponseEntity.ok("{\"ok\":true}"); } catch (FlowCallbackService.TransientCallbackException e) { log.error("[svc-hall] 回调瞬时失败(回 5xx 触发流程中心重试): {}", e.getMessage(), e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"ok\":false}"); } catch (Exception e) { // 意外异常同样按瞬时失败处理(宁可多重试一次,不可丢事件) log.error("[svc-hall] 回调意外异常(回 5xx 触发流程中心重试)", e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"ok\":false}"); } } }