我正在为 Go 中的 webhook 创建一个接收器,这是我在 Go 中的第一个应用程序。
我已经在本地测试了该应用程序,它在那里可以正常工作。但现在我已经将它部署在我的 Ubuntu 服务器上,位于 NGINX 代理后面的 Docker 容器中(代理在 Docker 之外)。 pingHandler 起作用,gitlabHandler 可以发送 403 消息。但如果 token 有效,我将始终看到 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 容器内不工作,正在创建日志文件,但它保持为空。所以此时我没有收到任何消息,除非有人知道这是为什么 ;-)
最佳答案
您是否尝试过查看 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。
关于Go 应用程序在 NGINX 代理 : HTTP 502 后面不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54065606/
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request