go - 启动 Go HTTP 服务器,做一些事情,然后在任务完成后将其关闭
问题描述
我正在从 CLI 应用程序设置 OAuth2 流,我正在处理。我需要为提供者创建一个临时 HTTP 服务器以将回调发送到,例如localhost:8080/callback
一旦提供商发送了我需要的详细信息,我希望能够关闭 HTTP 服务器,以保持一切清洁。我认为我正在寻找的是例程和等待组,但我对这个领域还是很陌生。
这就是我到目前为止所拥有的。token
我已经编辑了将用户发送到提供程序的部分,因为我的主要问题只是在捕获变量后如何关闭 HTTP 服务器。
- 服务器启动
- 用户被定向到提供者站点的授权 URL
- 用户批准请求
- 提供者将用户引导回
localhost:8080/callback
- URL 仅包含客户端参数,因此我必须服务器 HTML 以使用 JS 捕获值并将其发送回服务器
- 服务器收到令牌,然后可以关闭
package main
import (
"fmt"
"log"
"net/http"
"sync"
)
func main() {
// Start local HTTP serevr to listen for response
serverDone := &sync.WaitGroup{}
serverDone.Add(1)
Start(serverDone)
// ... Process to start OAuth2 flow
// User is directed to provider website
// User approves
// Provider direct user back to localhost/callback
serverDone.Wait()
}
func Start(wg *sync.WaitGroup) {
srv := &http.Server{Addr: ":8080"}
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
token := r.URL.Query().Get("token")
if token != "" {
fmt.Println("Found Token:", token)
// Shut down server here
} else {
// Server HTML page to fetch token and return to server at /callback
}
})
go func() {
// let main know we are done cleaning up
defer wg.Done()
// ErrServerClosed on graceful close
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("ListenAndServe(): %v", err)
}
}()
}
解决方案
利用:
var ctxShutdown, cancel = context.WithCancel(context.Background())
然后:
cancel() // to say sorry, above.
// graceful-shutdown
err := srv.Shutdown(context.Background())
尝试这个:
package main
import (
"context"
"fmt"
"log"
"net/http"
"sync"
)
func main() {
serverDone := &sync.WaitGroup{}
serverDone.Add(1)
Start(serverDone)
serverDone.Wait()
fmt.Println("Done that.")
}
var ctxShutdown, cancel = context.WithCancel(context.Background())
func Start(wg *sync.WaitGroup) {
srv := &http.Server{Addr: ":8080"}
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
select {
case <-ctxShutdown.Done():
fmt.Println("Sorry: Shuting down ...")
return
default:
}
token := r.URL.Query().Get("token")
if token != "" {
fmt.Println("Found Token:", token)
fmt.Println("Shuting down ...")
// Shut down server here
cancel() // to say sorry, above.
// graceful-shutdown
err := srv.Shutdown(context.Background())
if err != nil {
log.Println("server.Shutdown:", err)
}
} else {
fmt.Fprintln(w, "Hi") // Server HTML page to fetch token and return to server at /callback
}
})
go func() {
defer wg.Done()
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("ListenAndServe(): %v", err)
}
fmt.Println("Bye.")
}()
}
运行并打开http://127.0.0.1:8080/callback?token=2
输出:
Found Token: 2
Shuting down ...
Bye.
Done that.
推荐阅读
- java - 如果我有 50 个用户,如何在应用程序中为一个用户获取一个 JDBC 连接
- regex - 如何在 Emacs 主要模式下编写一个允许在行尾添加注释而不关闭该行的字体锁定的正则表达式
- r - R在数据框中按组捕获回归斜率
- android - JobService 不会在 android 9 中重新安排
- php - Stripe:即使 customer_id 不为空,也会创建新客户?
- javascript - 寻找 javascript 库来保存和恢复 html 表单,包括从 php 的 $_POST 恢复
- c# - 使用可变参数使此方法通用
- angular - Angular 7 ngBuild:require(filename) 不能在 forRoot() 方法中传递
- python - 使用 selenium 和 python 将鼠标移动到网页区域之外
- javascript - 是否可以从工作人员那里调用 SubtleCrypto 方法?