Go HTTP服务器记录202响应,但在一个函数后不关闭/发送响应

mwg9r5ms  于 2023-02-20  发布在  Go
关注(0)|答案(1)|浏览(149)

我有一个HTTP(Go)服务器端点,它接收到一个webhook POST,验证签名后,我得到了w.WriteHeader(http.StatusAccepted)
使用ngrok,如果我在下面提到的函数之前的各个点上简单地执行return,服务器就会正确地响应,我可以在ngrok中看到202响应,并且我的服务器日志显示202已经发送。
当我点击这个函数时,在那之后的任何时间,我的Go服务器日志都显示处理完成,并给出202的响应,我在到达端点函数末尾的过程中放入了不同的日志,每一个都打印成功,我记录了每一个错误,但没有错误,函数应该做的每一件事,它都完成了。
但是在调用特定函数之后,ngrok永远不会收到响应。
我试着刷新响应编写器,但没有任何效果(我知道我不应该这么做--我只是在尝试,因为我正在戳所有的东西),就好像Go语言正在挂起或处理某个东西,但我不知道是什么。
我想让你看得懂,但要知道我会记录和处理每一个错误(但不会收到任何错误):

// Using chi router but that shouldn't matter
r.Post("/webhook", func(w http.ResponseWriter, r *http.Request) {
    var payload webhookPayload
    b, err := io.ReadAll(r.Body)
    if err != nil {
        logger.logEntry(err, "info", r)
        w.WriteHeader(http.StatusBadRequest)
        return
    }
    defer r.Body.Close()

    // Validate webhook or send http.StatusUnauthorized and return
    w.WriteHeader(http.StatusAccepted)

    // Unmarshal body
    // Get oauth refresh token from credential manager
    // Get new tokens from oauth server
    // Update token in credential manager

    // None of the above produce errors and if I `return` now,
    // I can see the completed 202 response in ngrok

    // Here's where the problem is:
    purchases, err := getPurchases(ids, token, service)
    if err != nil {
        logger.logEntry(err, "critical", r)
        return
    }
    // I get no error from the above

    // This prints in the console
    fmt.Println("done processing")
    // After this prints, my Docker log shows: 202 0B in 2.501328168s
    // telling me it's done in 2.5s and should send the 202 with no body,
    // but ngrok doesn't receive it any time after getPurchases
})

getPurchases函数没有什么特别之处。service是一个接口,它的函数向API发出一个简单的HTTP GET请求,它 * 是 * 在检查错误后关闭请求主体,它调用data, err := io.ReadAll(res.Body)并在之后返回data, err

// This is the only place my getPurchases is doing anything outside of read data/update struct logic
func (s Service) GetPurchasesFromApi(ids string, token string) ([]byte, error) {
    queryURL := fmt.Sprintf("%s/purchases/%s", s.baseURL, ids)

    req, err := http.NewRequest("GET", queryURL, nil)
    if err != nil {
        return []byte{}, err
    }

    q := req.URL.Query()
    q.Add("version", fmt.Sprint(s.version))
    req.URL.RawQuery = q.Encode()

    req.Header.Add("Accept", "application/json")
    req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
    req.Header.Add("Content-Type", "application/text")

    res, err := s.httpClient.Do(req)
    if err != nil {
        return []byte{}, err
    }
    defer res.Body.Close()

    if res.StatusCode < 200 && res.StatusCode > 299 {
        return []byte{}, fmt.Errorf("got a status code of %d", res.StatusCode)
    }
    data, err := io.ReadAll(res.Body)
    return data, err
}

出于完成目的,使用的http客户端是在服务器启动之前在main中设置的客户端,并提供给Service用于其API调用:

httpClient := &http.Client{
    Transport: &http.Transport{
        MaxIdleConns:    10,
        IdleConnTimeout: 30 * time.Second,
    },
}

ngrok继续坐在那里,不断地监听响应,我的总处理时间从来没有超过3秒,所以这不是ngrok超时的情况。
有没有什么想法,我可以看看下一步来弄清楚这一点?或者有什么东西跳出来你?

xlpyo6sf

xlpyo6sf1#

根据提供的代码,该问题似乎与处理webhook后未向客户端发送响应有关。在代码中,向客户端发送了HTTP.StatusAccepted应答,表示服务器已收到并接受webhook。但是,服务器在处理getPurchases()函数后似乎未进一步响应。
要解决此问题,您需要在处理webhook后向客户端发送响应。您可以通过添加对w.Write()的调用来发送空响应正文沿着HTTP.StatusAccepted状态代码来完成此操作。例如:
w.写入标头(接受的http.状态)w.写入([]字节{})
这将发送一个带有HTTP.StatusAccepted状态代码的空响应正文,向客户端指示webhook已成功处理。
此外,您可能需要检查getPurchases()函数中是否有任何错误可能导致未发送响应的问题。您还可以尝试记录getPurchases()的响应,以查看它是否返回任何意外结果。
购买,如果错误!= nil { logger.logEntry(错误,“关键”,r)//enter code here. return } //enter code here.,则错误:=获取购买(ID、令牌、服务)
//记录购买fmt.Println(购买)
w.写入标头(接受的http.状态)w.写入([]字节{})

相关问题