# 链接预览开发指南

链接预览能力可以将飞书消息中的链接，转换为文字或卡片的形式进行展示。本文将介绍什么是链接预览，以及如何配置链接预览。

## 功能概述

链接预览是把飞书消息、群置顶等场景内包含的链接解析为带图标的文本内容，或者是一张具备结构化样式、可进行简单交互的卡片，以便消息接收者在不进行链接跳转的情况下，快速了解链接所包含的内容，或者通过卡片交互完成业务操作。

没有实现链接预览和已实现链接预览的效果如下所示，其中：

- 未实现链接预览时，飞书消息中的链接仅展示 URL，当用户查看消息时无法直接了解该 URL 包含的信息，必须点击访问后才可以进行下一步信息处理。
- 实现链接预览时，飞书消息中的链接会被解析为带图标的文本内容，或者附带一张包含链接内容概览的卡片。这样用户在查看消息时，可便捷直观的了解该链接所包含的内容。

![Frame 1.png](//sf3-cn.feishucdn.com/obj/open-platform-opendoc/21a955bd5e16e43332ba143490e44362_IDZwaPuTPn.png?height=1112&lazyload=true&maxWidth=700&width=2160)

更多链接预览的应用案例，可参见[典型案例](https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/development-link-preview/typical-case)。

## 实现方式

链接预览是飞书开放平台应用的能力之一。你可以在应用内定义 URL 规则，来指定生效预览能力的链接范围。在你本地业务服务器内，接收来自开放平台的链接预览回调请求，并通过响应请求的方式，实现链接预览的文本与卡片。链接预览能力在飞书中的实现流程如下图所示。

![image.png](//sf3-cn.feishucdn.com/obj/open-platform-opendoc/7053ab0f557687ee5a3d6c4884e76525_suTZoMJyyl.png?height=1148&lazyload=true&maxWidth=700&width=2000)

流程概述：
1. 查看者在飞书客户端的会话、群置顶等场景中查看链接。
2. 飞书将会通过应用的链接预览能力，校验该链接是否命中 URL 规则。

命中则继续执行下一步，未命中则不会对该链接进行解析。

3. 命中 URL 规则后，飞书会向你本地的业务服务器发送回调请求。
4. 在业务服务器内，你需要处理回调请求，并在 3 秒内响应该请求。

响应体中定义了链接预览的文本与卡片数据。

5. 在飞书客户端内，链接查看者可查看链接预览效果。

## 配置链接预览

本文以企业自建应用为例，介绍如何配置链接预览。商店应用的配置方式与企业自建应用类似。

### 步骤一：创建应用并启用链接预览能力

想要在飞书客户端内实现链接预览，需要在飞书开放平台创建一个应用并启用链接预览能力。企业自建应用发布后，链接预览将对[应用可用范围](https://open.feishu.cn/document/home/introduction-to-scope-and-authorization/availability)内的用户生效，即用户在发送消息时，链接如果命中 URL 规则，便会对应用可见范围内的用户展示预览效果。

应用开发流程参见[企业自建应用开发流程](https://open.feishu.cn/document/home/introduction-to-custom-app-development/self-built-application-development-process)或[商店应用上架流程](https://open.feishu.cn/document/uMzNwEjLzcDMx4yM3ATM/ugzNwEjL4cDMx4CO3ATM)。
- 当企业内安装了具备链接预览能力的应用后，链接预览所注册的 URL 规则只对**应用可用范围**内的用户生效。
- 仅正式版本的应用支持链接预览功能，且配置完成后需要发布应用使功能生效。测试版本的应用不支持配置链接预览。

#### 操作步骤

1. 登录[开发者后台](https://open.feishu.cn/app)。
2. 创建一个用于实现链接预览能力的应用。
3. 进入应用详情页，在左侧导航栏点击 **应用能力** > **添加应用能力**。
4. 在 **添加应用能力** 页面的 **按能力添加** 页签，找到并添加 **链接预览**。

![](//sf3-cn.feishucdn.com/obj/open-platform-opendoc/4b546c4ffa451a8138327d61da5acc7d_AQAw6sEsap.png?height=1282&lazyload=true&maxWidth=600&width=2868)

### 步骤二：注册链接预览的 URL 规则

链接预览的 URL 规则用于定义实现链接预览能力的链接范围。在 **链接预览** 功能页的 **①注册需要自定义预览的 URL 规则** 区域，你可以点击 **添加 URL 规则** 配置链接，最多可配置 10 个 URL 规则。

![image.png](//sf3-cn.feishucdn.com/obj/open-platform-opendoc/c26d345adf52b23afabc003a978f085b_7sXniihMth.png?height=594&lazyload=true&maxWidth=600&width=1464)

#### URL 规则输入要求

-   URL 规则的格式为 `Host:Port/Path`。示例值 `example.com/demo`
    - `Host`：URL 规则的域名部分，必填。
    - `Port`：端口号，选填。
    - `/Path`：子路径，选填。

- `Host:Port` 为主机地址，其中的 `Port` 是端口号、`/Path` 是子路径。示例值：`example.com/demo`

- 不能以 `https`、`http` 等 schema 开头。

- 不能在 `Host` 部分使用 IP 地址。`Host` 部分必须包含顶级域名、二级域名，且顶级域名、二级域名部分禁止使用通配符。无效的 URL 规则示例：`*.cn`、`example.*`、`example`

- 禁止注册包含恶意内容的非法网站为 URL 规则，开发者后台会对 URL 规则的安全性做校验。

#### URL 规则的匹配方式

链接预览能力提供了两种 URL 规则的注册匹配方式：warning
**注意**：配置 URL 规则时不能以 `https`、`http` 开头，但后续在飞书客户端内想要生效链接预览效果，对应的链接必须以 `https`、`http` 开头。

URL 规则匹配方式 | 说明
---|---
无通配符 | 你可以输入不包含通配符的 URL，该 URL 及其所有子路径均会匹配该应用的链接预览能力。<br>例如：应用 A 注册的 URL 规则为 `example.com`，安装该应用的租户下，用户发送、查看 `https://example.com/path?query` 时，会匹配应用 A 的 URL 规则。
有通配符 | 你可以输入包含通配符的 URL，此时系统会严格按照通配符生效链接预览。<br>- **使用 `*` 通配符定义 URL 规则**<br>- 域名内通过 `.` 分割为多个域名级别。顶级域名、二级域名部分禁止使用通配符，其他级别可使用 `*` 匹配剩下的所有内容。该通配符后边不能再有其他字符，即 `*` 无法跨域名级别匹配，且 `*` 必然是当前域名级别的结尾。<br>示例配置：`*.example.com`<br>- 路径内通过 `/` 分割为多层级路径。在每层路径内，可使用 `*` 匹配剩下的所有内容。该通配符后边不能再有其他字符，即 `*` 无法跨路径层级匹配，且 `*` 必然是当前路径层级的结尾。<br>示例配置：`example.com/*/task`<br>- **使用 `**` 通配符定义 URL 规则**<br>- 在域名内，通过 `**` 匹配整个域名左侧的内容，且该通配符的左侧不能再有其他字符。示例配置：<br>- 正确配置：`**.example.com`<br>- 错误配置：`a.**.example.com`<br>- 在路径内，通过 `**` 匹配整个路径右侧的内容，且该通配符的右侧不能再有其他字符。示例配置：<br>- 正确配置：`/a/b*/**`<br>- 错误配置：`/a/b*/**/c`<br>场景示例：<br>- 应用 A 注册的 URL 规则为 `**.example.com`，安装该应用的租户下，用户发送、查看 `https://business1.example.com`、`https://project1.business1.example.com` 时，均会匹配应用 A 的 URL 规则。<br>- 应用 B 注册的 URL 规则为 `example.com/**`，安装该应用的租户下，用户发送、查看 `https://example.com/path` 时，会匹配应用 B 的 URL 规则。

#### URL 规则的排他性

- 对于企业自建应用：当一个自建应用成功注册、并提交发布链接预览的 URL 规则后，本企业内的其他自建应用将无法注册任何与该 URL 规则有交集的规则。

例如，应用 A 注册了 `example.com`，同企业内的应用 B 尝试注册 `example.com/path` 时将会报错规则冲突，无法注册。
- 对于商店应用：当一个商店应用成功注册、并提交发布链接预览的 URL 规则后，其他商店应用将无法注册任何与该 URL 规则有交集的规则。

例如，应用 A 注册了 `example.com`，当应用 B 尝试注册 `example.com/path` 时将会报错规则冲突，无法注册。
- 如果自建应用和商店应用配置的 URL 规则出现交集，则优先生效自建应用的 URL 规则。
- 不能将飞书的保留域名注册为链接预览的 URL 规则。如果误注册了飞书的保留域名，开发者后台将会报错提示，并禁止提交该 URL 规则。

### 步骤三：配置订阅链接预览回调
**注意**：URL 规则和订阅回调的配置操作都是必须的，否则将会造成链接预览功能异常。

完成 URL 规则的配置后，你需要在 **配置订阅链接预览回调** 区域点击 **去配置**，跳转至 **事件与回调** 功能页[配置回调订阅方式](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/event-subscription-guide/callback-subscription/callback-overview)，然后订阅 [拉取链接预览数据（url.preview.get）](https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/development-link-preview/pull-link-preview-data-callback-structure)回调。

![image.png](//sf3-cn.feishucdn.com/obj/open-platform-opendoc/11e567bc996c101a29eac71693f01b02_AFM6WWxEEz.png?height=617&lazyload=true&maxWidth=600&width=1514)

后续当用户在飞书客户端发送、查看的链接命中当前应用的预览链接 URL 规则时，飞书服务器会向你注册的回调地址发送请求，请求包含了链接预览数据。示例回调数据如下：

```json
{
  "schema": "2.0",
  "header": { //回调的通用参数
    "event_id":"",
    "token": "vi57noNQoGbhxxxxxWmmWdlsSn3FTzk1",
    "create_time": "170134xxxxx18480",
    "event_type": "url.preview.get",
    "tenant_key": "736xxxxx260f175d",
    "app_id": "cli_a40xxxxxe57e100c"
  },
  "event": { //拉取链接预览回调的上下文参数
    "operator": { //查看链接的用户信息
      "tenant_key": "736588cxxxx175d",
      "user_id": "c3xxxxd1",
      "open_id": "ou_xxxxx54182ea7b8319f4d39823b79d2"
    },
    "host": "im_message", //链接所在的宿主场景。枚举包括：1.im_message 聊天消息；2.im_top_notice 群置顶
    "delivery_type": "url_preview", //当 "delivery_type": "url_preview" 表示回调来自链接预览
    "context": { //这个场景下具体的上下文参数
      "url": "https://example.com/test/111", //匹配 URL 规则的原链接
      "preview_token": "e28r7df2-xxxx-477d-a8d0-2e1eb9971234", //用于标识链接预览的凭证，在返回链接预览数据时要用
      "open_message_id": "om_191d914xxxxx81c97a609c6634521234", //触发链接预览的消息 ID
      "open_chat_id": "oc_20443194b65f9c8cf2935818dae31234" //触发链接预览的群 ID
    }
  }
}
```

### 步骤四：实现链接预览内容warning
- 链接预览支持千人千面，即不同用户的链接预览效果是独立拉取的，因此你需要确保预览内容的数据安全。如果涉及非公开数据请做好权限管控，避免数据泄露。
- 在人数较多的群聊、热点传播等场景，实现链接预览效果时会产生并发流量，因此建议业务以 400 QPS 为阈值评估并发流量，做好系统防护措施，无法处理的流量应做好降级方案。

服务端接收到回调请求后，需要在 3 秒内响应请求，并在响应体内定义链接预览内容。响应体结构如下（详细说明参见[拉取链接预览数据](https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/development-link-preview/pull-link-preview-data-callback-structure)）。查看该结构可知，链接预览有两种实现形式。

- **链接解析**：必选预览形式。通过 `inline` 字段，设置链接解析的文本与图标。该形式可以概括介绍链接对应的网页内容。
- **卡片**：可选预览形式。通过 `card` 字段，匹配指定的卡片 ID、版本、变量数据，以返回一张具备结构化样式、可进行简单交互的卡片。该形式可以通过卡片展示更加丰富的链接内容，包括可以直接通过卡片的交互能力管理链接对应的网页内容。如何配置卡片，可参见[飞书卡片概述](https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/feishu-cards/feishu-card-overview)。

```json
// 如需使用该示例代码，需要去除代码中以 // 开头的注释内容，并根据实际情况设置参数值。
{
        "inline": { //返回文字预览内容，这部分是必填必须要返回的
                "i18n_title": {
                        "zh_cn": "smart card 测试点击跳转 & 富文本" //链接预览文本
                },
                "image_key": "img_v3_025m_5xxxxxf9-ed30-4980-afff-827e13d8xxxx" //链接预览的前缀图标
        },
        "card": {//返回卡片预览内容
                "type": "template", //卡片的组织形式。枚举包括 1.template：模板方式，用如下结构返回卡片内容 2.raw 返回完整的卡片JSON内容
                "data": {
                        "template_id": "AAqVG2xxxxxBS", //必填，卡片的模板id
                        "template_version_name": "1.0.0", //选填，卡片的版本号。不填则表示使用最新发布版本的卡片
                        "template_variable": {} //选填，返回卡片绑定的变量列表数据
                }
        }
}
```

## 相关文档

- 上手体验链接预览能力，参见[快速入门](https://open.feishu.cn/document/uAjLw4CM/ukzMukzMukzM/development-link-preview/quick-start)。
- 开放平台提供了更新链接预览卡片的 OpenAPI，详情参见[更新 URL 预览](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/group/im-v2/url_preview/batch_update)。
更新链接预览时需要注意更新频率，如果更新时不指定用户，则可能会造成链接预览请求放大。例如，群聊中的链接预览，所有群成员均会尝试重新拉取预览请求。