#go #go-gin
#Вперед #go-gin
Вопрос:
При обращении gin-gonic
к нижеприведенному серверу HTTP-клиент должен получить код 500, но получает код 200.
package main
import (
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
)
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
r.Use(gzip.Gzip(gzip.DefaultCompression))
r.POST("/test", func(c *gin.Context) {
panic("test") // Server panic and client should receive code 500.
})
r.Run(":8080")
}
При доступе /test
с HTTP-клиента журнал go server выглядит так, как показано ниже, и возвращает код 500.
[GIN] 2020/09/28 - 10:23:14 | 500 | 67.2995ms | ::1 | POST "/test"
2020/09/28 10:23:14 [Recovery] 2020/09/28 - 10:23:14 panic recovered:
test
C:/path/to/myproject/main.go:16 (0x8f193f)
main.func1: panic("test")
Но HTTP-клиент получает код 200.
Когда я удаляю r.Use(gzip.Gzip(gzip.DefaultCompression))
, HTTP-клиент получает код 500.
Почему клиент получает код 200 с r.Use(gzip.Gzip(gzip.DefaultCompression))
, как я могу это исправить?
Комментарии:
1. Я не смог воспроизвести это. Получение кода 500 с промежуточным программным обеспечением gzip и без него.
2. @LLawliet какую версию вы используете? Я использую go 1.14.6, gin 1.6.3, gin-contrib / gzip 0.0.3
3. go 1.15.2, gin 1.6.3, gin-contrib / gzip 0.0.3
4. Я попробовал перейти на 1.15.2, но все равно получает код 200.
5. Как вы выполняете POST? Вероятно, я виноват в использовании curl без заголовков accept.
Ответ №1:
Я воспроизвел ваш случай. Postman получил код 200, но сервер выдает 500 вместо этого.
Сервер вызовет c.Next() для выполнения 4 обработчиков при получении post-запросов. Последовательность действий следующая:
gin.Logger
gin.Recovery
gzip.Gzip(gzip.DefaultCompression)
your handler
Вот gin ResponseWriter записывает заголовок ответа, и он будет записывать заголовок только один раз.
func (w *responseWriter) WriteHeaderNow() {
if !w.Written() {
w.size = 0
w.ResponseWriter.WriteHeader(w.status)
}
}
Оба gzip.Gzip(gzip.DefaultCompression)
и gin.Recovery
имеют функцию отсрочки для записи заголовка ответа. Отложенные вызовы Golang выполняются в порядке поступления первыми. Поэтому gzip.Gzip(gzip.DefaultCompression)
заголовок ответа будет записан в 200, а gin.Recovery
заголовок ответа не будет записан в 500, как ожидалось.
Поэтому, чтобы решить эту проблему, вы должны изменить порядок обработчиков и убедиться gin.Recovery
, что загружается последний обработчик.
Ответ №2:
Последнее добавление промежуточного программного обеспечения для восстановления, похоже, исправляет это.
package main
import (
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
)
func main() {
gin.SetMode(gin.ReleaseMode)
r := gin.New()
r.Use(gin.Logger())
r.Use(gzip.Gzip(gzip.DefaultCompression))
r.Use(gin.Recovery())
r.POST("/test", func(c *gin.Context) {
panic("test") // Server panic and client should receive code 500.
})
r.Run(":8080")
}