go web框架
- net/http
- gin-gonic/gin
- go-chi/chi
- gorilla/mux
其中gin 我是用的最多,但是在最近的使用中我有一些特殊需求,比如 /gitlab/{uuid}/notify,我只获取{uuid}的值才能满足,gin 不能更好的满足我的需求
这时候 gorilla/mux 就能满足我的需求
package main
import (
"context"
"errors"
"fmt"
"github.com/go-playground/webhooks/v6/gitlab"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"io"
"log"
"net/http"
"os"
"os/signal"
"time"
)
func gitlabWebhook(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
fmt.Println("ctx:", ctx)
XGitlabToken, ok := ctx.Value("X-Gitlab-Token").(string)
if !ok {
http.Error(w, http.StatusText(422), 422)
return
}
fmt.Println("X-Gitlab-Token", XGitlabToken)
fmt.Println("r.Header.Get(\"X-Gitlab-Token\")", r.Header.Get("X-Gitlab-Token"))
vars := mux.Vars(r)
name := vars["uuid"]
w.Write([]byte("Hello, " + name + "!"))
//hook, err := gitlab.New(gitlab.Options.Secret("122333"))
hook, err := gitlab.New()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
payload, err := hook.Parse(r, gitlab.PushEvents, gitlab.TagEvents, gitlab.MergeRequestEvents, gitlab.BuildEvents, gitlab.JobEvents, gitlab.PipelineEvents)
if err != nil {
if errors.Is(err, gitlab.ErrEventNotFound) {
// ok event wasn't one of the ones asked to be parsed
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if errors.Is(err, gitlab.ErrGitLabTokenVerificationFailed) {
// ok event wasn't one of the ones asked to be parsed
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
fmt.Println("err", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if payload == nil {
fmt.Println(payload)
}
switch payload.(type) {
case gitlab.MergeRequestEventPayload:
release := payload.(gitlab.MergeRequestEventPayload)
// Do whatever you want from here...
fmt.Printf("%+v", release)
case gitlab.PushEventPayload:
pushRequest := payload.(gitlab.PushEventPayload)
// Do whatever you want from here...
fmt.Printf("%+v", pushRequest)
case gitlab.TagEventPayload:
TagRequest := payload.(gitlab.TagEventPayload)
// Do whatever you want from here...
fmt.Printf("%+v", TagRequest)
}
_, err = io.WriteString(w, r.URL.Path)
if err != nil {
return
}
}
type Handler func(w http.ResponseWriter, r *http.Request) error
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if err := h(w, r); err != nil {
// handle returned error here.
w.WriteHeader(503)
w.Write([]byte("bad"))
}
}
// MyMiddleware HTTP middleware setting a value on the request context
func MyMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// create new context from `r` request context, and assign key `"user"`
// to value of `"123"`
ctx := context.WithValue(r.Context(), "X-Gitlab-Token", r.Header.Get("X-Gitlab-Token"))
// call the next handler in the chain, passing the response writer and
// the updated request object with the new context value.
//
// note: context.Context values are nested, so any previously set
// values will be accessible as well, and the new `"user"` key
// will be accessible from this point forward.
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func main() {
// 创建一个新的路由器
r := mux.NewRouter()
//// 定义一个路由
//r.HandleFunc("/gitlab/{uuid}/notify", func(w http.ResponseWriter, r *http.Request) {
// vars := mux.Vars(r)
// name := vars["uuid"]
// w.Write([]byte("Hello, " + name + "!"))
//}).Methods("POST")
r.Use(MyMiddleware)
r.HandleFunc("/gitlab/{uuid}/notify", gitlabWebhook).Methods("POST")
loggedRouter := handlers.LoggingHandler(os.Stdout, r)
srv := &http.Server{
Addr: ":8080",
// Good practice to set timeouts to avoid Slowloris attacks.
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: loggedRouter, // Pass our instance of gorilla/mux in.
}
go func() {
// 服务连接
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
//errChan <- err
log.Fatalf("listen: %s\n", err)
}
}()
c := make(chan os.Signal, 1)
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
signal.Notify(c, os.Interrupt)
// Block until we receive our signal.
<-c
wait := time.Second * 60
// Create a deadline to wait for.
ctx, cancel := context.WithTimeout(context.Background(), wait)
defer cancel()
// Doesn't block if no connections, but will otherwise wait
// until the timeout deadline.
srv.Shutdown(ctx)
// Optionally, you could run srv.Shutdown in a goroutine and block on
// <-ctx.Done() if your application should wait for other services
// to finalize based on context cancellation.
log.Println("shutting down")
os.Exit(0)
}

浙公网安备 33010602011771号