Golang和Gin Web框架 – 在router.Run()之后执行代码

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

Golang and Gin web framework - Execute code after router.Run()

问题

我对Go还比较新,如果这是一些显而易见的东西,请原谅我。

我正在使用Go编写一些关于OAuth 2.0身份验证的代码。其中一部分是我需要有一个可用的回调URL。在我的代码中,我需要创建一个回调端点,一旦它运行起来,我就需要调用一个授权端点,该端点将会访问我的回调端点。

我的问题是,在Gin中调用Run()会阻塞我的执行,所以在我的回调端点运行起来后,我无法进行进一步的授权。是否有一种方法可以在单独的GoRoutine中运行这段代码,以便我可以在回调后完成授权流程?

这是我主函数中代码的一个简单示例:

r := gin.Default()
// ReqHandler是一个HtttpHandler函数
r.GET("/redirect", ReqHandler)

r.Run(":5001")
ContinueAuth()
英文:

I am fairly new to Go, so please excuse me if this is something obvious.

I am busy writing some code in Go for OAuth 2.0 Authentication. Part of this means that I need to have a callback URL available. In my code I need to create a callback endpoint, and once this is up and running I need to call an Authorization endpoint which will then reach out to my callback endpoint.

My problem being that calling Run() in Gin is blocking my execution, so I can't do any further authorization after my callback endpoint is up and running. Is there a way to maybe run this code in a separate GoRoutine so that I can finish my Authorization flow afterwards?

Here is a rough example of my code in my main function:

r := gin.Default()
//ReqHandler is an HtttpHandler func
r.GET("/redirect", ReqHandler)

r.Run(":5001")
ContinueAuth()

答案1

得分: 3

在主goroutine中创建一个监听器。在一个goroutine中启动HTTP服务器。在主goroutine中继续进行身份验证流程。

r := gin.Default()
r.GET("/redirect", ReqHandler)

l, err := net.Listen("tcp", ":5001")
if err != nil {
    log.Fatal(err)
}

go func() {
   log.Fatal(r.RunListener(l))
}()

ContinueAuth()

select {} // 永远等待

在主goroutine中创建监听器可以确保监听器准备好接收身份验证流程的回调。

英文:

Create a listener in the main goroutine. Start the HTTP server in a goroutine. Continue with auth flow in the main goroutine.

r := gin.Default()
r.GET("/redirect", ReqHandler)

l, err := net.Listen("tcp", ":5001")
if err != nil {
    log.Fatal(err)
}

go func() {
   log.Fatal(r.RunListener(l))
}()

ContinueAuth()

select {} // wait forever

Creating the listener in the main goroutine ensures that the listener is ready for callbacks from the authentication flow.

答案2

得分: 0

注意:除非发生错误,否则此方法将无限期地阻塞调用的goroutine。

r.Run()将阻塞执行,除非发生错误。

可以通过将Run()作为go例程运行,并在其后运行ContinueAuth()来实现。

package main

import (
	"fmt"

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

func main() {
	r := gin.Default()

	r.GET("/redirect", ReqHandler)

	go func() {
		// serve and listen
		if err := r.Run(":8080"); err != nil {
			fmt.Println("Failed to start the server:", err)
			return
		}
	}()

	ContinueAuth()

	select {}
}

但是,即使Run引发错误,ContinueAuth也会运行。

因此,我们必须以不同的方式处理它,因为只有在服务器成功启动后,ContinueAuth()才应该运行。

  • 我们将创建一个仅包含信号的通道,并启动一个go例程来监听该通道。
  • 当通道接收到信号时,我们将调用ContinueAuth()
  • 我们将启动另一个go例程,在1秒后将信号发送到通道中。这是为了等待服务器运行或失败。
  • 启动服务器

以下是实现的代码:

package main

import (
	"fmt"
	"time"

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

func main() {
	r := gin.Default()

	r.GET("/redirect", ReqHandler)

	done := make(chan struct{}, 1)

	// 此go例程等待在done通道上接收到信号。
	// 当通道关闭时,我们知道服务器已成功运行
	// 如果服务器未成功运行,则表示监听出现了问题
	{
		go func(done chan struct{}) {
			// 检查通道是否关闭
			if _, ok := <-done; !ok {
				fmt.Println("通道已关闭.. 服务器已成功运行")
				ContinueAuth()
			}
		}(done)
	}

	// 在1秒后发送通道关闭信号....
	// 因为只有在服务器成功启动时才会运行此代码,
	// 否则此代码将不会执行,立即失败
	go func(done chan struct{}) {
		time.Sleep(time.Second) // 更新
		close(done)
	}(done)

	// 服务和监听
	if err := r.Run(":8080"); err != nil {
		fmt.Println("无法启动服务器:", err)
		return
	}

}

func ReqHandler(c *gin.Context) {
}

func ContinueAuth() {
	fmt.Println(".............. [ContinueAuth] ............... ")
}

希望对你有所帮助。

英文:

> Note: this method will block the calling goroutine indefinitely unless an error happens.

The r.Run() will block the execution unless an error happens.

It is possible by running the Run() as go-routine and ContinueAuth() after it by.

package main

import (
	&quot;fmt&quot;

	&quot;github.com/gin-gonic/gin&quot;
)

func main() {
	r := gin.Default()

	r.GET(&quot;/redirect&quot;, ReqHandler)

	go func() {
		// serve and listen
		if err := r.Run(&quot;:8080&quot;); err != nil {
			fmt.Println(&quot;Failed to start the server:&quot;, err)
			return
		}
	}()

	ContinueAuth()

	select {}
}

But ContinueAuth will run even when the Run raises an error too.

So we have to handle it differently, as the ContinueAuth() should only run after the server has successfully started.

  • We will create a signal only channel, and start a go routine to listen the channel.
  • When the signal received on the channel, we'll call ContinueAuth()
  • We'll start another go-routine to send the signal into channel after 1 second. This is to wait for the server to run or fail.
  • Start the server

Here is the implementation

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;

	&quot;github.com/gin-gonic/gin&quot;
)

func main() {
	r := gin.Default()

	r.GET(&quot;/redirect&quot;, ReqHandler)

	done := make(chan struct{}, 1)

	// this go routine wait for getting a signal in done channel.
	// On channel close, then we know the server is running successfully
	// If it is not running successfully, then it means something went wrong with the listening
	{
		go func(done chan struct{}) {
			// Check the channel is closed
			if _, ok := &lt;-done; !ok {
				fmt.Println(&quot;Channel is closed.. The server is running successfully&quot;)
				ContinueAuth()
			}
		}(done)
	}

	// send the channel close signal after 1 second....
	// as this will only run if the server started sucessfully,
	// else this code will not execute, the execution will fail at immediately
	//
	// We are assuming the server will fail within 1 second when something went wrong
	go func(done chan struct{}) {
		time.Sleep(time.Second) // updated
		close(done)
	}(done)

	// serve and listen
	if err := r.Run(&quot;:8080&quot;); err != nil {
		fmt.Println(&quot;Failed to start the server:&quot;, err)
		return
	}

}

func ReqHandler(c *gin.Context) {
}

func ContinueAuth() {
	fmt.Println(&quot;.............. [ContinueAuth] ............... &quot;)
}

Hope this helps

答案3

得分: 0

我已经接受了@thwd的答案,但我想添加我目前正在使用的解决方法,以防有人感兴趣(或者以防它有问题,有人想纠正我!)。

我使用了一个等待组,并在GoRoutine中启动了gin服务器:

func main(){
 var wg sync.WaitGroup

 wg.Add(1)

 go ConfigureGin(&wg)
 
 ContinueAuth()
 wg.Wait()
}

func ConfigureGin(wg *sync.WaitGroup){
 r := gin.Default()
 r.Get("/redirect",ReqHandler)
 r.Run(":5001")
 wg.Done()
}
英文:

I have accepted the answer from @thwd but I figured I would add the workaround that I am currently using in case anyone is interested (or in case it's bad and someone would like to correct me!).

I used a wait group and started the gin server in a GoRoutine:

func main(){
 var wg sync.WaitGroup

 wg.Add(1)

 go ConfigureGin(&amp;wg)
 
 ContinueAuth()
 wg.Wait()
}

func ConfigureGin(wg *sync.WaitGroup){
 r := gin.Default()
 r.Get(&quot;/redirect&quot;,ReqHandler)
 r.Run(&quot;:5001&quot;)
 wg.Done()
}

huangapple
  • 本文由 发表于 2023年6月24日 22:00:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76546411.html
匿名

发表评论

匿名网友

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

确定