---
title: SDM 拦截器使用指南 - 内置拦截器选型与自定义链路扩展
summary: SDM 拦截器用于在 SmartDeviceModel 的 init、request、response 链路中插入统一逻辑。本文聚焦 logger、dp-kit、matter-kit 的选型与组合方式，以及自定义拦截器的常见写法。
questions:
  - 什么时候应该使用 SDM 拦截器，什么时候直接使用 hooks 即可？
  - init、request、response 三类拦截点分别适合处理什么问题？
  - logger、dp-kit、matter-kit 分别解决什么场景，如何选型？
  - 为什么手动配置某条拦截器链后，默认 logger 会失效？
  - 多个拦截器按什么顺序执行，dp-kit 和 matter-kit 组合时为什么 dp-kit 要在前？
  - onInit 与 init.initDpState / init.initDevInfo 的区别是什么？
  - 自定义拦截器的 ctx、next、data 分别代表什么？
  - PublishDpsInterceptor 和 OnDpDataChangeInterceptor 分别适合用在什么地方？
---

# SDM 拦截器

<Alert type="warning">
自定义拦截器及其类型仍属于实验性能力。`logger`、`dp-kit`、`matter-kit` 可直接使用；若自行实现拦截器，请关注后续 API 调整。
</Alert>

`interceptors` 用来在 SDM 的初始化、下发和事件回调链路中插入统一逻辑，适合处理日志打印、协议转换、结构化数据映射以及条件短路等场景。

## 什么时候需要拦截器？

✅ **适合使用**：
- 需要在 `publishDps` 前后统一处理数据、日志或埋点
- 需要把设备原始上报转换为更适合业务消费的数据结构
- 需要复用 `logger`、`dp-kit`、`matter-kit`
- 多个页面都依赖同一套初始化或协议处理逻辑

❌ **不需要使用**：
- 只是单个页面的临时展示逻辑
- 只是读取简单 DP 功能点，`useProps / useActions` 已足够
- 不需要改写 SDM 初始化、下发或事件链路

## 内置拦截器怎么选？

| 拦截器 | 适用场景 | 核心能力 | 文档 |
| ----- | ----- | ----- | ----- |
| `logger` | 开发调试 | 打印 `init / request / response` 链路日志 | [logger](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/logger) |
| `dp-kit` | 复杂 DP 功能点 | 协议解析、结构化状态、下发选项 (sendOptions)、即时更新 | [dp-kit](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/dpkit/usage) |
| `matter-kit` | Matter 照明设备 | Matter 与标准 DP 双向转换，可与 `dp-kit` 组合 | [matter-kit](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/matterkit/usage) |

<Alert type="info">
SDM 默认会在内置链路上挂载 `logger`。但当你手动配置某个拦截器数组时，该链路会被新数组覆盖；如果仍需要日志，请把 `logger` 显式放回数组里。
</Alert>

## 接入方式

### Step 1: 选择拦截点

| 分类 | 可配置项 | 常见用途 |
| ----- | ----- | ----- |
| `init` | `initDpState`、`initDevInfo` | 初始化时修正 `dpState` 或 `devInfo` |
| `request` | `publishDps` | 下发前格式化、补充参数、节流 / 防抖 |
| `response` | `onDpDataChange`、`onDeviceInfoUpdated`、`onDeviceOnlineStatusUpdate`、`onNetworkStatusChange`、`onBluetoothAdapterStateChange` | 上报转换、状态同步、事件增强 |
| `onInit` | `(device) => void` | 设备初始化完成后的额外逻辑，例如 `dpKit.init(device)` |

### Step 2: 挂载到 SmartDeviceModel

> `src/devices/index.ts`

```ts | pure
import { SmartDeviceModel, createDpKit, logger } from '@ray-js/panel-sdk';
import { defaultSchema } from '@/devices/schema';

type SmartDeviceSchema = typeof defaultSchema;

const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
  },
});

const options = {
  interceptors: {
    onInit: (device) => {
      dpKit.init(device);
    },
    init: {
      initDpState: [logger, ...dpKit.interceptors.init.initDpState],
      initDevInfo: [logger, ...dpKit.interceptors.init.initDevInfo],
    },
    request: {
      publishDps: [logger, ...dpKit.interceptors.request.publishDps],
    },
    response: {
      onDpDataChange: [logger, ...dpKit.interceptors.response.onDpDataChange],
      onDeviceInfoUpdated: [logger, ...dpKit.interceptors.response.onDeviceInfoUpdated],
      onDeviceOnlineStatusUpdate: [logger],
      onNetworkStatusChange: [logger],
      onBluetoothAdapterStateChange: [logger],
    },
  },
};

export const devices = {
  common: new SmartDeviceModel<SmartDeviceSchema>(options),
};
```

如果只使用单个内置套件，也可以直接传入 `interceptors: dpKit.interceptors` 或 `interceptors: matterKit.interceptors`。

### Step 3: 处理多个拦截器的顺序

- 同一链路中的拦截器按数组顺序包裹执行；数组越靠前，越早接收到输入
- 如果某个拦截器不调用 `next(...)`，后续拦截器和底层方法都不会继续执行
- 同时使用 `dp-kit` 和 `matter-kit` 处理 `publishDps` 时，通常让 `dp-kit` 在前、`matter-kit` 在后

```ts | pure
request: {
  publishDps: [
    ...dpKit.interceptors.request.publishDps,
    ...matterKit.interceptors.request.publishDps,
  ],
},
```

## 自定义拦截器

### 常用类型

| 类型 | 对应链路 | 说明 |
| ----- | ----- | ----- |
| `Interceptor` | 通用 | 快速定义任意链路的通用拦截器 |
| `InitDpStateInterceptor` | `init.initDpState` | 初始化 `dpState` 前后的统一处理 |
| `InitDevInfoInterceptor` | `init.initDevInfo` | 初始化 `devInfo` 前后的统一处理 |
| `PublishDpsInterceptor` | `request.publishDps` | 改写下发参数、补充 DP 功能点或 options |
| `OnDpDataChangeInterceptor` | `response.onDpDataChange` | 将设备上报转换为业务态 |
| `OnDeviceInfoUpdatedInterceptor` | `response.onDeviceInfoUpdated` | 响应设备信息变化 |
| `OnDeviceOnlineStatusUpdateInterceptor` | `response.onDeviceOnlineStatusUpdate` | 响应上下线变化 |
| `OnNetworkStatusChangeInterceptor` | `response.onNetworkStatusChange` | 响应网络变化 |
| `OnBluetoothAdapterStateChangeInterceptor` | `response.onBluetoothAdapterStateChange` | 响应蓝牙状态变化 |

> 群组场景还有 `OnGroupDpDataChangeInterceptor` 与 `OnGroupInfoChangeInterceptor`，本文聚焦单设备 SDM 的常用链路。

### 执行模型

<Alert type="info">
拦截器采用三层柯里化写法：`ctx => next => data`。
</Alert>

| 参数 | 说明 |
| ----- | ----- |
| `ctx.type` | 当前拦截的链路名，例如 `publishDps` 或 `onDpDataChange` |
| `ctx.log` | 当前链路对应的日志对象，可调用 `log.info / log.warn / log.fatal` |
| `ctx.instance` | 当前 `SmartDeviceModel` 实例，可获取 `getDpState()`、`getDevInfo()` 等数据 |
| `next` | 下一个拦截器或底层方法；调用后链路才会继续 |
| `data` | 当前请求入参或事件回调数据 |

```ts | pure
const interceptor = (ctx) => (next) => (data) => {
  return next(data);
};
```

### 常见模式示例

**1. 在下发前补充或改写数据**

```ts | pure
import { PublishDpsInterceptor } from '@ray-js/panel-sdk';

export const appendExtraDp: PublishDpsInterceptor<SmartDeviceSchema> =
  (ctx) => (next) => (dpState, options) => {
    const nextDpState = {
      ...dpState,
      power_go: !ctx.instance.getDpState().power_go,
    };

    ctx.log.info('append extra dp before publishDps', nextDpState, 'appendExtraDp');

    return next(nextDpState, options);
  };
```

**2. 将原始上报转换为业务数据**

```ts | pure
import { DpState, DpValue, OnDpDataChangeInterceptor } from '@ray-js/panel-sdk';

export const mapDpsToDpState: OnDpDataChangeInterceptor<
  SmartDeviceSchema,
  DpState
> = (ctx) => (next) => (data) => {
  const devInfo = ctx.instance.getDevInfo();
  const dpState = {} as DpState;

  Object.keys(data.dps).forEach((dpId) => {
    dpState[devInfo.idCodes[dpId]] = data.dps[dpId] as DpValue;
  });

  return next(dpState);
};
```

**3. 在特定条件下短路后续链路**

```ts | pure
import { Interceptor } from '@ray-js/panel-sdk';

export const skipWhenReadonly: Interceptor<SmartDeviceSchema> =
  (ctx) => (next) => (data) => {
    const isReadonlyMode = true;

    if (isReadonlyMode) {
      ctx.log.info('skip current interceptor chain', data, 'skipWhenReadonly');
      return null;
    }

    return next(data);
  };
```

## 进阶阅读

### logger

> 查看默认日志拦截器的接入方式与类型定义

[logger 文档](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/logger)

### dp-kit

> 复杂 DP 功能点解析、sendOptions 和结构化 hooks 的完整用法

[dp-kit 使用指南](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/dpkit/usage)

### matter-kit

> Matter 照明设备的 DP 映射与组合方式

[matter-kit 使用指南](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/matterkit/usage)

### SmartDeviceModel

> `interceptors` 最终挂载在 SmartDeviceModel 上，完整初始化参数见 API 文档

[SmartDeviceModel 初始化 API](/cn/miniapp/solution-panel/ability/common/sdm/api/init)
