Gin gonic框架:易混淆的响应状态代码

hfyxw5xn  于 2023-06-27  发布在  Go
关注(0)|答案(1)|浏览(95)

我卷入了一件我不明白的事。
下面是一个用Golang编写的Gin API路由处理程序的示例。

// src/file1.go

func CreateDataModelAction(c *gin.Context) {
    var input inputs.CreateDataModelInput

    if err := c.ShouldBindJSON(&input); err != nil {
        // Here I use a function that generates and returns API responses for validation errors.
        // This function is located in separate file and it's going to be listed below this code        block.
        api.RespondWithValidationError(c, outputs.GetValidationErrors(err))
    return
    }

    c.JSON(http.StatusCreated, nil)
}
// src/file2.go

func RespondWithValidationError(c *gin.Context, validationErrors outputs.DataValidationErrorAPIResponse) {
    c.AbortWithStatusJSON(http.StatusUnprocessableEntity, validationErrors)
}

如果在ShouldBindJSON之后发生验证错误,我希望此代码进入if块并返回带有验证错误的422状态代码。然而,这段代码总是返回状态码200,尽管事实上thic函数只能返回422201
但是如果我删除api.RespondWithValidationError函数并直接在路由处理程序中使用AbortWithStatusJSON函数,我会收到预期的状态码422

// This example works as expected

func CreateDataModelAction(c *gin.Context) {
    var input inputs.CreateDataModelInput

    if err := c.ShouldBindJSON(&input); err != nil {
        c.AbortWithStatusJSON(http.StatusUnprocessableEntity)
    return
    }

    c.JSON(http.StatusCreated, nil)
}

我试图阅读Gin上下文源代码,以了解为什么会发生这种情况,到目前为止我还没有成功。
请向我解释Gin上下文在这种情况下是如何工作的,以及为什么当我从单独的函数返回422状态码时,我没有收到422

vybvopom

vybvopom1#

我根据你的问题的代码整理了一个小例子。我猜你省略的细节,但相关的代码应该是好的。我把所有的代码放在一个文件中,只是为了演示和更简洁。

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

// input DTO provided by HTTP Request
type createDataModeInput struct {
    Name string `json:"name" binding:"required"`
}

// output DTO to send in error scenario
type DataValidationErrorApiResponse struct {
    Code    string `json:"code"`
    Message string `json:"message"`
}

// function to build the DataValidationErrorApiResponse instance
func GetValidationErrors(err error) DataValidationErrorApiResponse {
    return DataValidationErrorApiResponse{
        Code:    "VALIDATION_ERR",
        Message: err.Error(),
    }
}

func RespondWithValidationError(c *gin.Context, validationErrors DataValidationErrorApiResponse) {
    c.AbortWithStatusJSON(http.StatusUnprocessableEntity, validationErrors)
}

func CreateDataModeAction(c *gin.Context) {
    var input createDataModeInput
    if err := c.ShouldBind(&input); err != nil {
        RespondWithValidationError(c, GetValidationErrors(err))
        return
    }
    c.JSON(http.StatusCreated, nil)
}

func main() {
    gin.SetMode(gin.DebugMode)
    r := gin.Default()
    r.POST("/demo", CreateDataModeAction)
    r.Run((":8000"))
}

正如你所看到的,代码与你的非常相似。现在,让我们看看如何正确地测试它。

CURL测试

为了测试代码,我使用了两个CURL命令:一个必须用422状态码解决,一个用201解决。后一个命令是:

curl -X POST http://127.0.0.1:8000/demo -H 'Content-Type: application/json' -d '{"name":"lorem"}'

这样,您将获得created - 201状态代码。要测试坏的场景,您应该使用以下命令:

curl -X POST http://127.0.0.1:8000/demo -H 'Content-Type: application/json' -d '{"name":""}'

使用此语句,您将获得所需的422状态代码。
对不起,如果我没有添加太多的解释,但代码真的很相似。如果你仍然面临一些问题,只是让我知道,我会更新我的答案,谢谢!

相关问题