无法中止上下文 – gin

huangapple go评论84阅读模式
英文:

Failed to Abort() context - gin

问题

我有以下的Gin中间件:

func CheckAppId(appC *core.Context) gin.HandlerFunc {
    return func(c *gin.Context) {
        //获取基本身份验证凭据
        appId, token, _ := c.Request.BasicAuth()

        if appId == "" {
            c.JSON(http.StatusOK, gin.H{"code": "MISSING_APP_ID", "message": "您的请求缺少应用程序ID"})
            return //这被忽略了吗?
        }

        c.Next() //这仍然会执行
    }
}

但是如果 appId == "",JSON会被返回,并且 c.Next() 也会被执行。这是预期的行为吗?

编辑
我以为问题已经解决,但似乎还是出现了同样的情况。现在我有:

func CheckAppId(appC *core.Context) gin.HandlerFunc {
    return func(c *gin.Context) {
        //获取基本身份验证凭据
        appId, token, _ := c.Request.BasicAuth()

        if appId == "" {
            //我在响应中得到了这个JSON
            c.JSON(http.StatusOK, gin.H{"code": "MISSING_APP_ID", "message": "您的请求缺少应用程序ID"})
            c.Abort()
        }

        //在数据库中查找app_id
        app := core.App{}
        err := appC.Database.C("apps").Find(bson.M{"id": appId}).One(&app)
        if err != nil { //未找到应用程序
            //我在响应中得到了这个JSON
            c.JSON(http.StatusOK, gin.H{"code": "INVALID_APP_ID", "message": "提供的应用程序ID无法找到"})
            c.Abort()
        }

        c.Next()
    }
}

在调用API时,我同时收到了 "MISSING_APP_ID" 的 JSON 和 "INVALID_APP_ID" 的 JSON。

英文:

I have the following Gin middleware:

func CheckAppId(appC *core.Context) gin.HandlerFunc {
    return func(c *gin.Context) {
        //get Basic Auth credentials
        appId, token, _ := c.Request.BasicAuth()

        if appId == "" {
            c.JSON(http.StatusOK, gin.H{"code": "MISSING_APP_ID", "message": "Your request is missing an application id"})
            return //this is being ignored???
        }
        
        c.Next() //this still gets hit
    }
}

but if the appId == "" the JSON gets returned and c.Next() gets executed too. Is this expected behaviour?

EDIT
I thought the problem had been sold but the same thing appears to be happening. I now have:

func CheckAppId(appC *core.Context) gin.HandlerFunc {
    return func(c *gin.Context) {
        //get Basic Auth credentials
        appId, token, _ := c.Request.BasicAuth()

        if appId == "" {
            //I'm getting this JSON in the response
            c.JSON(http.StatusOK, gin.H{"code": "MISSING_APP_ID", "message": "Your request is missing an application id"})
            c.Abort()
        }

        //find app_id in database
        app := core.App{}
        err := appC.Database.C("apps").Find(bson.M{"id" : appId}).One(&app)
        if err != nil { //no app found
            //and I'm getting this JSON in the response
            c.JSON(http.StatusOK, gin.H{"code": "INVALID_APP_ID", "message": "The application id provided could not be found"})
            c.Abort()
        }
       
        c.Next()
    }
}

In a call to the API I receive both "MISSING_APP_ID" Json and "INVALID_APP_ID" Json

答案1

得分: 8

根据Gin API文档,你需要调用context.Abort()而不是从你的方法中返回。

Abort()方法会停止系统继续调用链中的待处理程序。假设你有一个授权中间件,用于验证请求是否经过授权,如果授权失败(密码不匹配),应该调用该方法(Abort())来停止实际处理程序的执行。

所以在你的特定情况下:

if appId == "" {
    c.JSON(http.StatusOK, gin.H{"code": "MISSING_APP_ID", "message": "Your request is missing an application id"})
    c.Abort()
    return
}

请注意,以上是翻译的内容,不包括代码部分。

英文:

Looking at the Gin API docs, you'll need to call context.Abort() instead of returning from your method.

> Abort stops the system to continue calling the pending handlers in the chain. Let's say you have an authorization middleware that validates if the request is authorized if the authorization fails (the password does not match). This method (Abort()) should be called in order to stop the execution of the actual handler.

So in your specific case

if appId == "" {
    c.JSON(http.StatusOK, gin.H{"code": "MISSING_APP_ID", "message": "Your request is missing an application id"})
    c.Abort()
    return
}

答案2

得分: 4

TL;DR

你需要这样做:

if condition {
  c.Abort()
} else {
  c.Next()
}

解释:

(注意:这是基于@Landers的答案)

c.Abort()只是设置一些内部标志,以特定的方式标记上下文,表示异常终止。这是有道理的,它是一个无参数的方法,不返回任何内容,所以你只是为了它的副作用而调用它。

c.Next()也是同样的道理。

由于Go语言的控制流程(没有异常或跳转),很明显这两个方法不会立即采取任何行动,而是为下一阶段做准备。想象一下Gin代码调用你的CheckAppId函数:

// gin代码
doStuff()
ctx := getContext()

// 这是你的CheckAppId
nextAction := FindAction()
nextAction(&ctx)

// 在这里,上下文被评估,以确定是中止还是继续。
checkContextStatus(&ctx)

所以,如果你先调用c.Abort(),然后再调用c.Next(),你就会覆盖中止的指示。

英文:

TL;DR

You need to do:

if condition {
  c.Abort()
} else {
  c.Next()
}

Explanation

(Note: this builds on @Landers answer)

c.Abort() just sets some internal flags that mark the context in a certain way that indicates abnormal termination. It makes sense, it's a parameterless method that returns nothing, so you're only calling it for its side-effects.

Same thing with c.Next()

Because of go's control flow (no exceptions or jumps) its clear that these two methods don't take any immediate action but "set up the stage" for the next phase, imagine Gins code that calls your CheckAppId func:

// gin code
doStuff()
ctx := getContext()

// this is your CheckAppId
nextAction := FindAction()
nextAction(&ctx)

// here the context is evaluated to see if you either abort or continue.
checkContextStatus(&ctx)

So, if you're calling c.Abort() and then c.Next() you're overriding the abort indications.

huangapple
  • 本文由 发表于 2015年9月9日 04:49:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/32467002.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定