webhook 是什么以及如何创建

jettyhan · · 11465 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

我们在网上做的工作,大部分其实就是事件,webhooks 已经成为了连接系统的主要方式,不管是用户创建、支付成功、DockerHub 镜像推送或者 Git 仓库上的合并请求,这些都是非常有用并且轻量级的共享信息的方式 ![](https://raw.githubusercontent.com/studygolang/gctt-images/master/webhook/1.png) 那么,webhook 究竟是什么呢?webhook 是应用给其它应用提供实时信息的一种方式。信息一产生,webhook 就会把它发送给已经注册的应用,这就意味着你能实时得到数据。不像传统的 APIs 方式,你需要用轮询的方式来获得尽可能实时的数据。这一点使得 webhook 不管是在发送端还是接收端都非常高效。由于大部分服务提供商对 API 的访问有一定限制,所以要么采用 webhook 方式,要么采用传统的轮询方式,不过这样客户端数据会有一些(或者比较多的)滞后。上面的图是用户发起的一个典型的支付流程的示例。 Webhook 有时被叫做「反向 APIs」,因为它返回的信息和正常 API 返回的差不多,并且你还得设计一个 webhook 可以使用的 API。webhook 会向你的应用发送一个 HTTP 请求(通常使用 POST 方式),然后你的应用负责解析这个请求。你可以把它当成一个客户端发来的常规 API 请求,不过这时候它是一个你依赖的一个第三方的服务。 现在许多开发者都在使用比较流行的服务(比如 Strip、GitHub)提供的 webhook,你可能也想让用户接收你的应用产生的 webhook。这篇文章里,我们就是要创建这样一个简单的应用,让其它用户可以注册并且接收这个应用产生的事件。 ## 创建一个 webhhook 分发应用 我们的这个应用将使用 Go 语言编写([这里](https://golang.org/doc/install) 有 Go 语言的安装指南),但是你可以选择任何其它的语言来实现这个应用,这只是一个展示 webhook 功能的简单的例子。代码非常简单,即使你对 Go 不熟悉也很容易读懂。 ``` go package main import ( "bytes" "encoding/json" "fmt" "log" "net/http" "sync" "time" ) // port - default port to start application on const port = ":8090" type WebhookRequest struct { Name string Destination string } func main() { dispatcher := &Dispatcher{ client: &http.Client{}, destinations: make(map[string]string), mu: &sync.Mutex{}, } // preparing HTTP server srv := &http.Server{Addr: port, Handler: http.DefaultServeMux} // webhook registration handler http.HandleFunc("/webhooks", func(resp http.ResponseWriter, req *http.Request) { dec := json.NewDecoder(req.Body) var wr WebhookRequest err := dec.Decode(&wr) if err != nil { resp.WriteHeader(http.StatusBadRequest) return } dispatcher.add(wr.Name, wr.Destination) }) // start dispatching webhooks go dispatcher.Start() fmt.Printf("Create webhooks on http://localhost%s/webhooks \n", port) // starting server err := srv.ListenAndServe() if err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } } type Dispatcher struct { client *http.Client destinations map[string]string mu *sync.Mutex } func (d *Dispatcher) Start() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-ticker.C: d.dispatch() } } } func (d *Dispatcher) add(name, destination string) { d.mu.Lock() d.destinations[name] = destination d.mu.Unlock() } func (d *Dispatcher) dispatch() { d.mu.Lock() defer d.mu.Unlock() for user, destination := range d.destinations { go func(user, destination string) { req, err := http.NewRequest("POST", destination, bytes.NewBufferString(fmt.Sprintf("Hello %s, current time is %s", user, time.Now().String()))) if err != nil { // probably don't allow creating invalid destinations return } resp, err := d.client.Do(req) if err != nil { // should probably check response status code and retry if it's timeout or 500 return } fmt.Printf("Webhook to '%s' dispatched, response code: %d \n", destination, resp.StatusCode) }(user, destination) } } ``` ## 运行这个webhook 应用 要使用这个 webhook 应用,我们需要一个可以接收 webhook 消息并且调试的一个终端。为了完成这个任务,我们选择了 [https://bin.webhookrelay.com/](https://bin.webhookrelay.com/) 这个免费的服务。打开这个链接后,会被重定向到一个唯一的地址,那个就是我们要使用的终端地址,后面我们很快就会用到这个地址。 接下来让我们启动这个应用: ``` $ go run main.go Create webhooks on http://localhost:8090/webhooks ``` 现在把刚才生成的终端地址注册到我们的应用里: ``` curl --request POST \ --url http://localhost:8090/webhooks \ --header 'content-type: application/json' \ --data '{ "name": "joe", "destination": "https://bin.webhookrelay.com/v1/webhooks/821024d7-12a0-4b41-99f2-71fcc2906989" }' ``` 注册完以后,我们应该很快看到日志信息: ![](https://raw.githubusercontent.com/studygolang/gctt-images/master/webhook/2.png) 在网页终端里应该会看到应用发来的请求: ![](https://raw.githubusercontent.com/studygolang/gctt-images/master/webhook/3.png) ## 总结 总的说,webhook 和普通的 API 请求是一样的,都是事件,都是为了在系统间共享信息。API 轮询在之前可能是一个比较好的解决方案,但是如果有过多的用户采用这种方式,可能给服务器带来很大的负担甚至导致当机。 ### 要成功实现一个 webhook 需要考虑以下几点: - 用户应该可以指定 webhook 的地址 - 大多数系统只允许连接到一个 webhook, 你可能需要允许链接到多个 - 如果请求的返回码大于 500, 则重新请求。可能有人认为当请求返回的是 4 开头的值时,才应该重新请求,因为这说明刚才的请求是无效的 如果对 webhook 感兴趣,可以看一下我们写的一些 [例子](https://webhookrelay.com/v1/examples/receiving-webhooks-on-localhost.html),从这些例子里你可以学会如何接收本地或者局域网 webhook 发送的信息。总之 webhook 非常灵活。 2018 年 7 月 13 号发表于 [webhookrelay.com](https://webhookrelay.com/blog/2018/07/13/how-to-create-webhook/)

via: https://itnext.io/what-is-a-webhook-and-how-to-create-one-f7057d2cc0a

作者:Karolis Rusenas  译者:jettyhan  校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

11465 次点击  ∙  2 赞  
加入收藏 微博
被以下专栏收入,发现更多相似内容
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传