ABOUTYOU
正如评论中所写,webhook 只是一个事件发生的通知,并且可能会发送一些数据,通常作为 JSON 数据。您有责任保留事件本身以及您想要/需要处理的随它发送的数据。您将在下面找到一个注释示例。请注意,这不包括增量退避,但这应该很容易添加:package mainimport ( "encoding/json" "flag" "io" "log" "net/http" "os" "path/filepath" "github.com/joncrlsn/dque")var ( bind string queueDir string segmentSize int)// You might want to add request headers and stufftype webhookContent struct { Foo string Bar int}func init() { flag.StringVar(&bind, "bind", ":8080", "The address to bind to") flag.StringVar(&queueDir, "path", "./queue", "path to store the queue in") flag.IntVar(&segmentSize, "size", 50, "number of entries for the queue")}// The "webserver" componentfunc runserver(q *dque.DQue) { http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) { // A new decoder for each call, as we want to have a new LimitReader // for each call. This is a simple, albeit a bit crude method to prevent // accidental or malicious overload of your server. dec := json.NewDecoder(io.LimitReader(r.Body, 4096)) defer r.Body.Close() c := &webhookContent{} if err := dec.Decode(c); err != nil { log.Printf("reading body: %s", err) http.Error(w, "internal error", http.StatusInternalServerError) return } // When the content is successfully decoded, we can persist it into // our queue. if err := q.Enqueue(c); err != nil { log.Printf("enqueueing webhook data: %s", err) // PROPER ERROR HANDLING IS MISSING HERE } }) http.ListenAndServe(bind, nil)}func main() { flag.Parse() var ( q *dque.DQue err error ) if !dirExists(queueDir) { if err = os.MkdirAll(queueDir, 0750); err != nil { log.Fatalf("creating queue dir: %s", err) } } if !dirExists(filepath.Join(queueDir, "webhooks")) { q, err = dque.New("webhooks", queueDir, segmentSize, func() interface{} { return &webhookContent{} }) } else { q, err = dque.Open("webhooks", queueDir, segmentSize, func() interface{} { return &webhookContent{} }) } if err != nil { log.Fatalf("setting up queue: %s", err) } defer q.Close() go runserver(q) var ( // Placeholder during event loop i interface{} // Payload w *webhookContent // Did the type assertion succeed ok bool ) for { // We peek only. The semantic of this is that // you can already access the next item in the queue // without removing it from the queue and "mark" it as read. // We use PeekBlock since we want to wait for an item in the // queue to be available. if i, err = q.PeekBlock(); err != nil { // If we can not peek, something is SERIOUSLY wrong. log.Fatalf("reading from queue: %s", err) } if w, ok = i.(*webhookContent); !ok { // If the type assertion fails, something is seriously wrong, too. log.Fatalf("reading from queue: %s", err) } if err = doSomethingUseful(w); err != nil { log.Printf("Something went wrong: %s", err) log.Println("I strongly suggest entering an incremental backoff!") continue } // We did something useful, so we can dequeue the item we just processed from the queue. q.Dequeue() }}func doSomethingUseful(w *webhookContent) error { log.Printf("Instead of this log message, you can do something useful with: %#v", w) return nil}func dirExists(path string) bool { fileInfo, err := os.Stat(path) if err == nil { return fileInfo.IsDir() } return false}现在,当您执行以下操作时:$ curl -X POST --data '{"Foo":"Baz","Bar":42}' http://localhost:8080/webhook你应该得到一个日志条目2020/04/18 11:34:23 Instead of this log message, you can do something useful with: &main.webhookContent{Foo:"Baz", Bar:42}