功能设计-如何设计一个回调功能

功能设计-如何设计一个回调功能

回调功能实现详解

一、回调功能概述

回调(Callback)是一种常见的异步编程模式,主要用于服务间的异步通信。当服务A需要服务B执行某个耗时操作时,服务A不会一直等待服务B完成,而是提供一个回调地址,服务B完成操作后主动通知服务A。

二、回调流程详解

1. 流程步骤

请在此添加图片描述

  1. 客户端触发操作:用户或系统通过客户端发起请求到服务A
  2. 服务A调用服务B:服务A将任务委托给服务B,并传递回调URL
  3. 服务B处理任务:服务B开始执行实际业务逻辑
  4. 服务B回调通知:任务完成后,服务B调用预先提供的回调URL
  5. 服务A后续处理:服务A收到回调后执行后续业务逻辑

2. 关键组件说明

  • 回调URL:服务A暴露的HTTP端点,用于接收服务B的通知
  • 异步调用:服务A调用服务B时不会阻塞等待
  • 任务标识:通常需要唯一ID关联请求和回调(简化版未展示)

三、代码实现

请在此添加图片描述

服务A代码实现

  1. 双端点架构
    • /start:启动工作流
    • /callback:接收回调通知
  2. 关键处理逻辑
    • 收到启动请求后,立即调用服务B
    • 同步响应客户端避免阻塞
    • 在回调端点处理服务B完成通知
  3. 异步通信原则
    • go callServiceB() 确保非阻塞调用
    • 回调机制解除服务依赖
package main

import (
    "fmt"
    "log"
    "net/http"
    "strings"
)

func main() {
    fmt.Println("启动服务A (监听 :8080)")

    // 设置HTTP路由
    http.HandleFunc("/start", startHandler)
    http.HandleFunc("/callback", callbackHandler)

    log.Fatal(http.ListenAndServe(":8080", nil))
}

// 开始请求处理
func startHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("服务A: 收到新请求")

    // 调用服务B
    go callServiceB()

    fmt.Fprint(w, "任务已提交,处理中...")
}

// 调用服务B
func callServiceB() {
    fmt.Println("服务A: 调用服务B")

    // 设置回调地址
    callbackURL := "http://localhost:8080/callback"

    // 构造服务B请求
    serviceBURL := "http://localhost:8081/task"
    payload := fmt.Sprintf(`{"callback_url": "%s"}`, callbackURL)

    // 发送HTTP请求
    _, err := http.Post(serviceBURL, "application/json",
       strings.NewReader(payload))

    if err != nil {
       log.Printf("调用服务B失败: %v", err)
    }
}

// 回调处理
func callbackHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("服务A: 收到服务B的回调")
    fmt.Println("服务A: 执行后续操作...")

    fmt.Fprint(w, "回调已接收")
}

服务B代码实现

  1. 任务处理核心
    • 接收包含回调URL的任务请求
    • 解析JSON格式的回调地址
    • 异步处理耗时任务
    • 完成后发送回调通知
  2. 关键处理流程
    • 解析请求 → 验证参数 → 异步处理 → 发送回调
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strings"
    "time"
)

func main() {
    fmt.Println("启动服务B (监听 :8081)")

    // 设置HTTP路由
    http.HandleFunc("/task", taskHandler)

    log.Fatal(http.ListenAndServe(":8081", nil))
}

// 请求结构体
type TaskRequest struct {
    CallbackURL string `json:"callback_url"`
}

// 任务处理
func taskHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("服务B: 收到新任务")

    // 解析JSON请求
    var req TaskRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
       http.Error(w, "无效请求数据: "+err.Error(), http.StatusBadRequest)
       log.Printf("请求解析错误: %v", err)
       return
    }

    // 获取回调URL
    callbackURL := req.CallbackURL
    if callbackURL == "" {
       http.Error(w, "缺少回调URL", http.StatusBadRequest)
       return
    }

    fmt.Printf("服务B: 开始处理任务,回调URL: %s\n", callbackURL)

    // 异步处理任务
    go func() {
       // 模拟处理时间(3秒)
       time.Sleep(3 * time.Second)

       fmt.Println("服务B: 任务处理完成")

       // 发送回调通知
       sendCallback(callbackURL)
    }()

    fmt.Fprint(w, "任务已开始处理")
}

// 发送回调
func sendCallback(callbackURL string) {
    fmt.Printf("服务B: 发送回调至 %s\n", callbackURL)

    // 发送回调通知
    payload := `{"status": "完成", "message": "任务处理成功"}`
    _, err := http.Post(callbackURL, "application/json", strings.NewReader(payload))

    if err != nil {
       log.Printf("回调发送失败: %v", err)
       return
    }

    fmt.Println("服务B: 回调发送成功")
}

使用方式

  • 首先启动两个服务

请在此添加图片描述

请在此添加图片描述

  • 然后访问A服务的Start接口

请在此添加图片描述

  • 然后两个服务就请求和回调成功了

请在此添加图片描述

请在此添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客李华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值