MSHA控制台提供切流结束接口回调功能,支持切流结束后进行业务自定义接口的回调。

使用限制

一个多活命名空间下,最多允许配置3个回调接口。

控制台操作步骤

  1. 登录AHAS控制台,然后在页面左上角选择地域
  2. 在控制台左侧导航栏中选择多活容灾
  3. 在左侧导航栏选择基础配置 > 切流回调配置
  4. 单击切流回调配置页面右上角的添加,配置以下参数。
    参数 描述
    回调URL 回调接口的URL:
    • 管控与此URL根IP具备网络连通性,建议测试网络连通性后再进行配置
    • URL需要包含协议头,例如:http://xx.domain.com/yy。
    回调条件

    回调触发条件:

    • 切流结束:切流结束后触发(无论成功还是异常)。
    • 切流成功:仅切流成功结束后触发。
    • 切流失败:仅切流异常结束后触发。
    HTTP请求方法 回调采用的HTTP/HTTPS请求方法。枚举值为:GET、POST。
    安全摘要盐值 盐,用于对回调请求生成安全摘要。
  5. 单击保存。在确认的对话框中单击确认

规范

使用接口回调功能时,回调接口需要满足以下规范。

  • 回调接口需是HTTP/HTTPS协议。
  • 回调接口需要免登,即不做登录态校验。
  • 回调接口不能有CSRF Token校验。
  • 回调接口参数名需要遵循以下名称规范。MSHA控制台发起回调时,会固定带上以下名称的参数,包含了切流工单基本信息和安全校验摘要。
    参数 参数描述
    mshaTenantId 多活命名空间ID。
    id 切流工单ID。
    name 切流工单名称。
    sourceUnitFlag 切流源单元标识,表示从sourceUnitFlag->向targetUnitFlag切流。
    targetUnitFlag 切流目的单元,表示从sourceUnitFlag->向targetUnitFlag切流。
    status

    切流结束状态。

    • 正常结束状态枚举值为:
      • complete:正常结束。
      • canceled:人为取消终止。
    • 异常结束状态枚举值为:
      • autoCanceled:异常后自动取消终止(回滚完成)。
      • cancelFailed:取消失败。
      • closed:强制关闭(不继续执行也不回滚)。
      • fail:其他情况异常终止。
    completeTime 切流结束时间。
    changeTokenRange

    当范围类型切流时,切流变更的范围区间。当非范围类型切流时,值为空字符串("")。

    格式:[$区间开始,$区间结束],其中 [] 括号表示数学上的闭区间(固定为闭区间,不会有开区间或半开区间的情况)。

    Java语言赋值样例:String changeTokenRange="[1,9999]";

    changeTokenList

    当精准类型切流时,切流变更的精准名单。当非精准类型切流时,值为空字符串("")。

    格式:以英文半角逗号隔开的精准名单。

    Java语言赋值样例:String changeTokenList="11,22,33";

    digest 安全摘要,用于验证调用是否可信以及参数防篡改。

回调接口样例

以下是Java语言版本,使用Spring MVC框架的编写的回调接口样例:

@RestController
@RequestMapping("/demo")
@Slf4j
public class DemoController {

    @RequestMapping(path = "/switchEndCallback", method = {RequestMethod.POST, RequestMethod.GET})
    public void switchEndCallback(  @RequestParam String mshaTenantId,
                                    @RequestParam String id,
                                    @RequestParam String name,
                                    @RequestParam String sourceUnitFlag,
                                    @RequestParam String targetUnitFlag,
                                    @RequestParam String status,
                                    @RequestParam String completeTime,
                                    @RequestParam String changeTokenRange,
                                    @RequestParam String changeTokenList,
                                    @RequestParam String digest) throws Exception {

        //do something
    }

}     

校验调用来源是否可信

MSHA控制台接口回调时,会带上digest安全摘要参数,用于验证调用来源是否可信以及参数防篡改。校验流程如下:

  1. 自定义一个digestSalt值,并将digestSalt配置到MSHA控制台切流结束回调接口信息中。
  2. 切流结束后,接口调用者(MSHA控制台)将发起接口回调,使用digestSalt和回调参数生成摘要digest,并在回调时带上该digest参数。
  3. 接口提供者(业务应用/业务系统)接收到回调接口时,使用跟步骤2一样的方式生成期望的摘要expectedDigest,跟回调参数中的摘要digest做比较。若完全相同表示验证通过,调用来源是否可信且参数没有被篡改。
    说明 仅当接口调用者和接口提供者都使用相同盐值和参数生成的摘要才会验证通过。

使用示例如下:

@RestController
@RequestMapping("/demo")
@Slf4j
public class DemoController {


    @RequestMapping(path = "/switchEndCallback", method = {RequestMethod.POST, RequestMethod.GET})
    public Object switchEndCallback(@RequestParam String mshaTenantId,
                                    @RequestParam String id,
                                    @RequestParam String name,
                                    @RequestParam String sourceUnitFlag,
                                    @RequestParam String targetUnitFlag,
                                    @RequestParam String status,
                                    @RequestParam String completeTime,
                                    @RequestParam String changeTokenRange,
                                    @RequestParam String changeTokenList,
                                    @RequestParam String digest) throws Exception {

        //使用TreeMap保证后续拼接的StringBuilder是固定顺序的TreeMap<String, String> sortedParamMap = new TreeMap<>();
        sortedParamMap.put("mshaTenantId", mshaTenantId);
        sortedParamMap.put("id", id);
        sortedParamMap.put("name", name);
        sortedParamMap.put("sourceUnitFlag", sourceUnitFlag);
        sortedParamMap.put("targetUnitFlag", targetUnitFlag);
        sortedParamMap.put("status", status);
        sortedParamMap.put("completeTime", completeTime);
        sortedParamMap.put("changeTokenRange", changeTokenRange);
        sortedParamMap.put("changeTokenList", changeTokenList);

        log.info("switchEndCallback params:" + sortedParamMap);

        //盐值,在请求参数生成安全摘要时使用,用于验证调用来源是否可信String digestSalt = "kbBO1nD1BM_Ymr76XOoZkbJ72k4";

        StringBuilder paramsStringBuilder = new StringBuilder();
        for (Map.Entry<String, String> entry : sortedParamMap.entrySet()) {
            paramsStringBuilder.append(entry.getValue());
        }
        paramsStringBuilder.append(digestSalt);

        //推荐使用commons-codec:commons-codec:jar:1.10(或以上版本)DigestUtils来生成md5哈希摘要String expectedDigest = org.apache.commons.codec.digest.DigestUtils.md5Hex(paramsStringBuilder.toString().getBytes("utf-8"));
        //只有接口调用者和接口提供者,都使用相同盐值、相同的参数生成的摘要才会验证通过boolean digestCheckPassed = digest.equalsIgnoreCase(expectedDigest);
        log.info("switchEndCallback digestCheckPassed:{}", digestCheckPassed);
        return "switchEndCallback returned success";
    }

}