1 - Bindings 概述
使用 Dapr 的绑定 API,您可以通过来自外部系统的事件触发您的应用程序,并与外部系统进行交互。通过绑定 API,您可以:
- 避免连接和轮询消息系统(如队列和消息总线)的复杂性。
- 专注于业务逻辑,而不是与系统交互的实现细节。
- 使您的代码不包含 SDK 或库。
- 处理重试和故障恢复。
- 在运行时切换绑定。
- 构建可移植的应用程序,使用特定环境的绑定设置,无需更改代码。
例如,通过绑定,您的应用程序可以响应传入的 Twilio/SMS 消息,而无需:
- 添加或配置第三方 Twilio SDK
- 担心从 Twilio 轮询(或使用 WebSockets 等)

在上图中:
- 输入绑定触发应用程序上的方法。
- 在组件上执行输出绑定操作,例如
"create"。
绑定是独立于 Dapr 运行时开发的。您可以查看并贡献绑定。
输入绑定
使用输入绑定,您可以在外部资源发生事件时触发您的应用程序。可选的有效负载和元数据可能会随请求一起发送。
以下概述视频和演示演示了 Dapr 输入绑定的工作原理。
要接收来自输入绑定的事件:
- 定义描述绑定类型及其元数据(连接信息等)的组件 YAML。
- 使用以下方式监听传入事件:
- HTTP 端点
- gRPC proto 库以获取传入事件。
注意
在启动时,Dapr 会向应用程序发送所有已定义输入绑定的 OPTIONS 请求。如果应用程序想要订阅绑定,Dapr 期望状态代码为 2xx 或 405。阅读使用输入绑定创建事件驱动应用程序指南以开始使用输入绑定。
输出绑定
使用输出绑定,您可以调用外部资源。可选的有效负载和元数据可以随调用请求一起发送。
以下概述视频和演示演示了 Dapr 输出绑定的工作原理。
要调用输出绑定:
- 定义描述绑定类型及其元数据(连接信息等)的组件 YAML。
- 使用 HTTP 端点或 gRPC 方法调用绑定,可选择携带有效负载。
- 指定输出操作。输出操作取决于您使用的绑定组件,可以包括:
"create""update""delete""exec"
阅读使用输出绑定与外部资源交互指南以开始使用输出绑定。
绑定方向(可选)
您可以提供 direction 元数据字段来指示绑定组件支持的方向。这样做可以避免 Dapr 边车处于"等待应用程序就绪"状态,从而减少 Dapr 边车与应用程序之间的生命周期依赖关系:
"input""output""input, output"
注意
强烈建议所有输入绑定都应包含direction 属性。尝试绑定
快速入门和教程
想要测试 Dapr 绑定 API?通过以下快速入门和教程来了解绑定的实际操作:
| 快速入门/教程 | 描述 |
|---|---|
| 绑定快速入门 | 使用输入绑定响应事件,使用输出绑定调用操作,与外部系统协作。 |
| 绑定教程 | 演示如何使用 Dapr 为其他组件创建输入和输出绑定。使用 Kafka 绑定。 |
直接在您的应用程序中开始使用绑定
想要跳过快速入门?没问题。您可以直接在应用程序中尝试绑定构建块,以调用输出绑定和触发输入绑定。在安装 Dapr后,您可以从输入绑定操作指南开始使用绑定 API。
后续步骤
2 - 操作指南:使用输入绑定触发应用程序
使用输入绑定,当外部资源发生事件时,可以触发您的应用程序。外部资源可以是队列、消息管道、云服务、文件系统等。请求可以随附可选的 payload 和 metadata。
输入绑定非常适合事件驱动处理、数据管道,或通常用于响应事件并执行进一步处理。Dapr 输入绑定允许您:
- 接收事件而无需包含特定的 SDK 或库
- 更换绑定而无需更改代码
- 专注于业务逻辑而非事件资源实现

本指南以 Kafka 绑定为例。您可以从绑定组件列表中找到您首选的绑定规范。在本指南中:
- 示例使用
checkout(要调用的绑定名称)调用/binding端点。 - payload 放入必填的
data字段中,可以是任何 JSON 可序列化的值。 operation字段告知绑定需要采取什么操作。例如,Kafka 绑定支持create操作。- 您可以检查每个输出绑定支持哪些操作(特定于每个组件)。
注意
如果您还没有尝试过,请先尝试绑定快速入门,快速了解如何使用绑定 API。创建绑定
创建一个 binding.yaml 文件并保存到应用程序目录中的 components 子文件夹。
创建一个名为 checkout 的新绑定组件。在 metadata 部分,配置以下与 Kafka 相关的属性:
- 您将向其发布消息的 topic
- broker
创建绑定组件时,指定绑定支持的 direction。
在 dapr run 命令中使用 --resources-path 标志指向您的自定义资源目录。
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: checkout
spec:
type: bindings.kafka
version: v1
metadata:
# Kafka broker 连接设置
- name: brokers
value: localhost:9092
# consumer 配置:topic 和 consumer group
- name: topics
value: sample
- name: consumerGroup
value: group1
# publisher 配置:topic
- name: publishTopic
value: sample
- name: authRequired
value: false
- name: direction
value: input
要部署到 Kubernetes 集群,运行 kubectl apply -f binding.yaml。
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: checkout
spec:
type: bindings.kafka
version: v1
metadata:
# Kafka broker 连接设置
- name: brokers
value: localhost:9092
# consumer 配置:topic 和 consumer group
- name: topics
value: sample
- name: consumerGroup
value: group1
# publisher 配置:topic
- name: publishTopic
value: sample
- name: authRequired
value: false
- name: direction
value: input
监听传入事件(输入绑定)
配置您的应用程序以接收传入事件。如果您使用 HTTP,则需要:
- 监听一个
POST端点,端点名称为绑定名称,即binding.yaml文件中metadata.name指定的名称。 - 验证您的应用程序允许 Dapr 对此端点进行
OPTIONS请求。
以下是利用 Dapr SDK 演示输入绑定的代码示例。
以下示例演示如何使用 ASP.NET Core 控制器配置输入绑定。
using System.Collections.Generic;
using System.Threading.Tasks;
using System;
using Microsoft.AspNetCore.Mvc;
namespace CheckoutService.controller;
[ApiController]
public sealed class CheckoutServiceController : ControllerBase
{
[HttpPost("/checkout")]
public ActionResult<string> getCheckout([FromBody] int orderId)
{
Console.WriteLine($"Received Message: {orderId}");
return $"CID{orderId}";
}
}
以下示例演示如何使用 minimal API 方式配置相同的输入绑定:
app.MapPost("checkout", ([FromBody] int orderId) =>
{
Console.WriteLine($"Received Message: {orderId}");
return $"CID{orderId}"
});
以下示例演示如何使用 minimal API 方式配置相同的输入绑定:
app.MapPost("checkout", ([FromBody] int orderId) =>
{
Console.WriteLine($"Received Message: {orderId}");
return $"CID{orderId}"
});
//dependencies
import org.springframework.web.bind.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
//code
@RestController
@RequestMapping("/")
public class CheckoutServiceController {
private static final Logger log = LoggerFactory.getLogger(CheckoutServiceController.class);
@PostMapping(path = "/checkout")
public Mono<String> getCheckout(@RequestBody(required = false) byte[] body) {
return Mono.fromRunnable(() ->
log.info("Received Message: " + new String(body)));
}
}
#dependencies
import logging
from dapr.ext.grpc import App, BindingRequest
#code
app = App()
@app.binding('checkout')
def getCheckout(request: BindingRequest):
logging.basicConfig(level = logging.INFO)
logging.info('Received Message : ' + request.text())
app.run(6002)
//dependencies
import (
"encoding/json"
"log"
"net/http"
"github.com/gorilla/mux"
)
//code
func getCheckout(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var orderId int
err := json.NewDecoder(r.Body).Decode(&orderId)
log.Println("Received Message: ", orderId)
if err != nil {
log.Printf("error parsing checkout input binding payload: %s", err)
w.WriteHeader(http.StatusOK)
return
}
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/checkout", getCheckout).Methods("POST", "OPTIONS")
http.ListenAndServe(":6002", r)
}
//dependencies
import { DaprServer, CommunicationProtocolEnum } from '@dapr/dapr';
//code
const daprHost = "127.0.0.1";
const serverHost = "127.0.0.1";
const serverPort = "6002";
const daprPort = "3602";
start().catch((e) => {
console.error(e);
process.exit(1);
});
async function start() {
const server = new DaprServer({
serverHost,
serverPort,
communicationProtocol: CommunicationProtocolEnum.HTTP,
clientOptions: {
daprHost,
daprPort,
}
});
await server.binding.receive('checkout', async (orderId) => console.log(`Received Message: ${JSON.stringify(orderId)}`));
await server.start();
}
确认事件
从您的 HTTP 处理程序返回 200 OK 响应,告知 Dapr 您已成功处理事件。
拒绝事件
返回 200 OK 以外的任何响应,告知 Dapr 事件在您的应用程序中未正确处理,并计划重新传递该事件。例如,返回 500 Error。
指定自定义路由
默认情况下,传入事件将发送到与输入绑定名称对应的 HTTP 端点。您可以通过在 binding.yaml 中设置以下 metadata 属性来覆盖此设置:
name: mybinding
spec:
type: binding.rabbitmq
metadata:
- name: route
value: /onevent
事件传递保证
事件传递保证由绑定实现控制。根据绑定实现的不同,事件传递可以是恰好一次或至少一次。
参考
3 - 操作指南:使用输出绑定与外部资源交互
使用输出绑定,您可以调用外部资源。调用请求中可以发送可选的有效负载和元数据。

本指南以 Kafka 绑定为例。您可以从绑定组件列表中找到您需要的绑定规范。在本指南中:
- 示例通过调用
/binding端点,并传递checkout(要调用的绑定名称)来执行操作。 - 有效负载放入必需的
data字段中,可以是任何可序列化为 JSON 的值。 operation字段告诉绑定需要执行什么操作。例如,Kafka 绑定支持create操作。- 您可以查看每个输出绑定支持的操作(特定于各组件)。
注意
如果您还没有尝试过,可以先体验绑定快速入门,快速了解如何使用绑定 API。创建绑定
创建一个 binding.yaml 文件,并将其保存到应用程序目录中的 components 子文件夹中。
创建一个名为 checkout 的新绑定组件。在 metadata 部分中,配置以下与 Kafka 相关的属性:
- 您要向其发布消息的主题
- 代理
创建绑定组件时,指定绑定的受支持的 direction。
使用 dapr run 命令时,通过 --resources-path 标志指向您的自定义资源目录。
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: checkout
spec:
type: bindings.kafka
version: v1
metadata:
# Kafka broker 连接设置
- name: brokers
value: localhost:9092
# 消费者配置:主题和消费者组
- name: topics
value: sample
- name: consumerGroup
value: group1
# 发布者配置:主题
- name: publishTopic
value: sample
- name: authRequired
value: false
- name: direction
value: output
要将以下 binding.yaml 文件部署到 Kubernetes 集群中,请运行 kubectl apply -f binding.yaml。
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: checkout
spec:
type: bindings.kafka
version: v1
metadata:
# Kafka broker 连接设置
- name: brokers
value: localhost:9092
# 消费者配置:主题和消费者组
- name: topics
value: sample
- name: consumerGroup
value: group1
# 发布者配置:主题
- name: publishTopic
value: sample
- name: authRequired
value: false
- name: direction
value: output
发送事件(输出绑定)
下面的代码示例利用 Dapr SDK 来调用运行中的 Dapr 实例上的输出绑定端点。
以下是在 .NET 6+ 中使用顶级语句的控制台应用程序示例:
using System.Text;
using System.Threading.Tasks;
using Dapr.Client;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDaprClient();
var app = builder.Build();
const string BINDING_NAME = "checkout";
const string BINDING_OPERATION = "create";
var random = new Random();
using var daprClient = app.Services.GetRequiredService<DaprClient>();
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(5));
var orderId = random.Next(1, 1000);
await client.InvokeBindingAsync(BINDING_NAME, BINDING_OPERATION, orderId);
Console.WriteLine($"Sending message: {orderId}");
}
//dependencies
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.domain.HttpExtension;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
import java.util.concurrent.TimeUnit;
//code
@SpringBootApplication
public class OrderProcessingServiceApplication {
private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class);
public static void main(String[] args) throws InterruptedException{
String BINDING_NAME = "checkout";
String BINDING_OPERATION = "create";
while(true) {
TimeUnit.MILLISECONDS.sleep(5000);
Random random = new Random();
int orderId = random.nextInt(1000-1) + 1;
DaprClient client = new DaprClientBuilder().build();
//使用 Dapr SDK 调用输出绑定
client.invokeBinding(BINDING_NAME, BINDING_OPERATION, orderId).block();
log.info("Sending message: " + orderId);
}
}
}
#dependencies
import random
from time import sleep
import requests
import logging
import json
from dapr.clients import DaprClient
#code
logging.basicConfig(level = logging.INFO)
BINDING_NAME = 'checkout'
BINDING_OPERATION = 'create'
while True:
sleep(random.randrange(50, 5000) / 1000)
orderId = random.randint(1, 1000)
with DaprClient() as client:
#使用 Dapr SDK 调用输出绑定
resp = client.invoke_binding(BINDING_NAME, BINDING_OPERATION, json.dumps(orderId))
logging.basicConfig(level = logging.INFO)
logging.info('Sending message: ' + str(orderId))
//dependencies
import (
"context"
"log"
"math/rand"
"time"
"strconv"
dapr "github.com/dapr/go-sdk/client"
)
//code
func main() {
BINDING_NAME := "checkout";
BINDING_OPERATION := "create";
for i := 0; i < 10; i++ {
time.Sleep(5000)
orderId := rand.Intn(1000-1) + 1
client, err := dapr.NewClient()
if err != nil {
panic(err)
}
defer client.Close()
ctx := context.Background()
//使用 Dapr SDK 调用输出绑定
in := &dapr.InvokeBindingRequest{ Name: BINDING_NAME, Operation: BINDING_OPERATION , Data: []byte(strconv.Itoa(orderId))}
err = client.InvokeOutputBinding(ctx, in)
log.Println("Sending message: " + strconv.Itoa(orderId))
}
}
//dependencies
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";
//code
const daprHost = "127.0.0.1";
(async function () {
for (var i = 0; i < 10; i++) {
await sleep(2000);
const orderId = Math.floor(Math.random() * (1000 - 1) + 1);
try {
await sendOrder(orderId)
} catch (err) {
console.error(e);
process.exit(1);
}
}
})();
async function sendOrder(orderId) {
const BINDING_NAME = "checkout";
const BINDING_OPERATION = "create";
const client = new DaprClient({
daprHost,
daprPort: process.env.DAPR_HTTP_PORT,
communicationProtocol: CommunicationProtocolEnum.HTTP,
});
//使用 Dapr SDK 调用输出绑定
const result = await client.binding.send(BINDING_NAME, BINDING_OPERATION, orderId);
console.log("Sending message: " + orderId);
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
您也可以使用 HTTP 来调用输出绑定端点:
curl -X POST -H 'Content-Type: application/json' http://localhost:3601/v1.0/bindings/checkout -d '{ "data": 100, "operation": "create" }'
观看此视频了解如何使用双向输出绑定。