Teams Toolkit 之 Incoming Webhook
上一篇文章介绍了如何使用 teams toolkit 来快速创建一个最最简单的 teams app:incoming webhook。这篇文章我们就来深入看一下 incoming webhook的代码,我自己的学习方法就是花时间把一个新东西理解透彻后,再学另一个,因为一旦深入理解一个东西后,会发现很多知识是相通的。
我们先来看一下teams toolkit 生成的文件。
.fx
文件夹,这里面放置的是一些 teams toolkit 会用到的配置文件,如果如何配置 azure 等等,我们以后会详细的讲这块.vscode
文件夹,这里面是vscode用到的一些配置文件,对于我们这个简单的teams app来说,它很标准化,如果是一个复杂的 teams app,比如 bot,这里面还是挺有学问的,我们讲到 bot app后再做展开images
。这里面的图片主要是给 README 使用的,可以忽略,我们也可以删掉它incoming-webhook
文件夹,这里面是我们真正的代码,下面前三个文件比较重要,我们后面展开讲adaptiveCards
里面是 adaptive card 的模板文件index.ts
我们程序的入口webhookTarget.ts
辅助类似的代码,用来给 Teams 发送请求tsconfig.json
因为sample使用typescript开发的,所以这个文件里是typescript的一些设置,比如使用ES的标准之类的东西。package.json
标准的 node应用的项目文件,可以看到里面已经为我们定义好了几个命令,我们可以用来编译,运行,调试{ "scripts": { "dev": "nodemon -e ts --exec node --inspect=9239 --signal SIGINT -r ts-node/register ./src/index.ts", "build": "tsc --build", "start": "node ./lib/src/index.js", "watch": "nodemon --watch ./src -e ts --exec \"npm run start\"" } }
templates
文件夹,里面是 teams app 需要的 manifest.json 文件,由于我们这个sample是最最简单的 incoming webhook,所以不需要 manifest。manifest.template.json
文件是空的
了解了上面的文件结构后,我们来看一下整个应用的入口代码 index.ts
const webhookUrl: string = "https://teetee365.webhook.office.com/.......";
const webhookTarget = new WebhookTarget(new URL(webhookUrl));
webhookTarget.sendAdaptiveCard(
AdaptiveCards.declare(template).render(
{
"title": "New Event Occurred!",
"appName": "Contoso App",
"description": "Detailed description of what happened so the user knows what's going on.",
"notificationUrl" : "https://www.adaptivecards.io/"
}))
.then(() => console.log("Send adaptive card successfully."))
.catch(e => console.log(`Failed to send adaptive card. ${e}`));
代码非常简单,基本就是一句话,webhookTarget.sendAdaptiveCard()
,往 webhook 上发送一个 adaptive card,如果大家对 adaptive card 不太了解的话,可以参考这个网站 https://www.adaptivecards.io/,它是一种界面的描述性的代码,打开 notification-default.json
文件,我们看到下面的json。
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": "${title}",
"size": "Large",
"weight": "Bolder",
"wrap": true
},
{
"type": "TextBlock",
"text": "${appName}",
"isSubtle": true,
"color": "Accent",
"weight": "Bolder",
"size": "Small",
"spacing": "None"
},
{
"type": "TextBlock",
"text": "${description}",
"isSubtle": true,
"wrap": true
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "View Details",
"url": "${notificationUrl}"
}
]
}
上面这个配置我们一看就能想象到界面的样子,有三个文字块 (TextBlock
),每块里面有一个文件的 placeholder,用 ${blablabla}
表示,最后有一个可以交互的动作 (action
),用来打开一个网页url。我们对照一下最终在teams 里面的效果,就一目了然了。
那我们来修改一下这个 adaptive card 的 json,加一张图片试试看。我们把上面的json改成如下内容。
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": "Tony's Cat",
"size": "Large",
"weight": "Bolder",
"wrap": true
},
{
"type": "Image",
"url": "https://adaptivecards.io/content/cats/1.png",
"altText": "Tony's Cat"
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "Go to Microsoft",
"url": "https://www.microsoft.com"
}
]
}
然后运行 npm run build
,再运行 npm run start
,我们在 teams 里就可以看到效果了。
到这里我想各位基本知道是怎么回事了,我们最后再来看一下 webhookTarget.ts
,看看代码里到底是怎么发送消息给 teams 的。
public sendAdaptiveCard(card: unknown): Promise<void> {
return axios.post(
this.webhook.toString(),
{
type: "message",
attachments: [
{
contentType: "application/vnd.microsoft.card.adaptive",
contentUrl: null,
content: card,
},
],
},
{
headers: { "content-type": "application/json" },
}
);
}
看到这里,我相信各位已经已经明白了,实际上 incoming webhook 就是发送了一个简单的 http request 给到 webhook url,这个http request 的内容是一个特殊结构的 json,仅此而已,
看到这里,如果是有 node 开发经验的读者可能在想,实际上一句话就可以完成这些功能。我们另起一个 node 程序,在 ts 的入口文件里,写这么几行:
import axios from "axios";
axios.post(
"https://teetee365.webhook.office.com/......",
{
type: "message",
attachments: [
{
contentType: "application/vnd.microsoft.card.adaptive",
contentUrl: null,
content: {
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{ "type": "TextBlock", "text": "Tony's Cat (new)", "size": "Large", "weight": "Bolder", "wrap": true },
{ "type": "Image", "url": "https://adaptivecards.io/content/cats/1.png", "altText": "Tony's Cat" }
],
"actions": [
{ "type": "Action.OpenUrl", "title": "Go to Microsoft", "url": "https://www.microsoft.com" }
]
},
},
],
},
{
headers: { "content-type": "application/json" },
}
);
看到这里是不是有一种恍然大悟的感觉?希望通过这种简化,抛开sample code里的各种干扰,能让大家更好的理解 incoming webhook 的本质。