我正在Go中创建Webhooks的接收器,这是我在Go中的第一个应用程序。
我已经在本地测试了该应用程序,并且可以在那儿工作。但是现在我已经将它部署在NGINX代理后面的Docker容器中的Ubuntu服务器上(该代理位于Docker外部)。 pingHandler
有效,gitlabHandler
可以发送403消息。但是,如果令牌有效,我将始终看到一条502消息,NGINX日志会告诉我:
*1115 upstream prematurely closed connection while reading response header from upstream, client: X.X.X.X, server: myserver.home.example, request: "POST /webhookreceiver/gitlab HTTP/1.1", upstream: "http://127.0.0.1:7080/gitlab", host: "myserver.home.example"
此外,当我发送无效的JSON有效负载时,它仍然会给出相同的错误消息,因此,如果我正确理解该错误,我的Go应用程序会在第72-76行之前关闭连接。我猜第65行有问题吗?
对于大多数遇到此问题的其他人来说,可以通过增加超时来解决此问题,因为他们的请求太大,但是在我的情况下,我正在使用仅几个字节的JSON消息进行测试。
main.go
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"time"
)
type ServerConfig struct {
Https bool `json:"https"`
Cert string `json:"cert"`
Key string `json:"key"`
Gitlabtoken string `json:"gitlab_token"`
}
type SplunkConfig struct {
Token string
Url string
Metadata map[string]string
}
type SplunkEvent struct {
Host string `json:"host"`
Sourcetype string `json:"sourcetype"`
Index string `json:"index"`
Source string `json:"source"`
Event map[string]interface{} `json:"event"`
}
var splunk_config SplunkConfig
var server_config ServerConfig
type middleware func(next http.HandlerFunc) http.HandlerFunc
func withLogging(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Printf("IP %s", r.RemoteAddr)
next.ServeHTTP(w, r)
}
}
func chainMiddleware(mw ...middleware) middleware {
return func(final http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
last := final
for i := len(mw) - 1; i >= 0; i-- {
last = mw[i](last)
}
last(w, r)
}
}
}
func gitlabHandler(w http.ResponseWriter, req *http.Request) {
// Check if GitLab token is present and correct
gitlab_header := req.Header.Get("X-Gitlab-Token")
if gitlab_header == server_config.Gitlabtoken {
// Create SplunkEvent to send to Splunk
body, err := ioutil.ReadAll(req.Body)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Error reading body"))
return
}
var event map[string]interface{}
err = json.Unmarshal(body, &event)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("400 - Request cannot be parsed"))
return
}
se := SplunkEvent{
Host: splunk_config.Metadata["host"],
Sourcetype: splunk_config.Metadata["sourcetype"],
Index: splunk_config.Metadata["index"],
Source: "gitlab",
Event: event}
j, err := json.Marshal(se)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Error creating forwarding call"))
return
}
// Send SplunkEvent to Splunk
b := bytes.NewBuffer(j)
client := &http.Client{
Timeout: time.Second * 30,
}
req, err := http.NewRequest("POST", splunk_config.Url, b)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Error creating request"))
return
}
req.Header.Add("Authorization", "Splunk "+splunk_config.Token)
resp, err := client.Do(req)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Error sending request"))
return
}
// Check response
bod, err := ioutil.ReadAll(resp.Body)
if strings.Contains(string(bod), "Success") {
log.Println("Received and succesfully processed request")
w.WriteHeader(http.StatusOK)
w.Write([]byte("200 - OK"))
return
} else {
log.Println(string(bod))
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("500 - Error sending to Splunk"))
return
}
defer resp.Body.Close()
} else {
log.Println("Incorrect Gitlab token")
w.WriteHeader(http.StatusForbidden)
w.Write([]byte("403 - Forbidden"))
return
}
}
func pingHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Received ping call")
fmt.Fprint(w, "{\"check\": \"online\"}")
}
func main() {
// Setup logging
file, err := os.OpenFile("webhookreceiver.log", os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatal("Error opening log file: " + err.Error())
}
defer file.Close()
log.SetOutput(file)
// Load Splunk config
data, err := ioutil.ReadFile("configs/splunk.json")
if err != nil {
log.Fatal("Error reading splunk_config.json: " + err.Error())
}
err = json.Unmarshal(data, &splunk_config)
if err != nil {
log.Fatal("Error on unmarshal of Splunk config: " + err.Error())
}
// Load server config
data, err = ioutil.ReadFile("configs/server.json")
if err != nil {
log.Fatal("Error reading server_config.json: " + err.Error())
}
err = json.Unmarshal(data, &server_config)
if err != nil {
log.Fatal("Error on unmarshal of Server config: " + err.Error())
}
// Start server
log.Println("Starting server")
mw := chainMiddleware(withLogging)
http.Handle("/gitlab", mw(gitlabHandler))
http.HandleFunc("/ping", mw(pingHandler))
if server_config.Https {
log.Fatal(http.ListenAndServeTLS(":7443", server_config.Cert, server_config.Key, nil))
} else {
log.Fatal(http.ListenAndServe(":7080", nil))
}
}
NGINX配置的相关位
server {
listen 443 ssl;
listen [::]:443 ssl;
ssl_certificate /blabla/fullchain.pem;
ssl_certificate_key /blabla/privkey.pem;
client_max_body_size 3M;
add_header Strict-Transport-Security "max-age=31536000" always;
location /webhookreceiver/ {
proxy_pass http://127.0.0.1:7080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
我的Go应用程序的日志记录也在本地运行,但不在Docker容器内部运行,正在创建日志文件,但它保持为空。所以在这一点上,我没有任何消息,除非有人知道为什么;-)
答案 0 :(得分:0)
您是否尝试查看Docker日志而不是无效的日志文件?首先获取容器ID:
docker container ls
然后获取日志:
docker logs 14eb7d0a2332
nginx错误意味着您的Golang应用程序接受了该连接,但是关闭了该连接而没有返回响应。这表明您的Webhook正在返回而没有编写响应。
请求成功后,您的gitlabHandler似乎没有返回响应,您要做的最后一件事是读取上游响应:
bod, err := ioutil.ReadAll(resp.Body)
if strings.Contains(string(bod), "Success") {
log.Println("Received and succesfully processed request")
} else {
log.Println(string(bod))
}
defer resp.Body.Close()
您需要在此处写入ResponseWriter。