【问题标题】:How can I start the browser AFTER the server started listening?服务器开始监听后如何启动浏览器?
【发布时间】:2015-12-20 16:32:47
【问题描述】:

在 Go 中,如何在服务器开始监听后启动浏览器?

最好是最简单的方法。

到目前为止,我的代码非常简单:

package main

import (  
    // Standard library packages
    "fmt"
    "net/http"
    "github.com/skratchdot/open-golang/open"
    // Third party packages
    "github.com/julienschmidt/httprouter"
)


// go get github.com/toqueteos/webbrowser

func main() {  
    // Instantiate a new router
    r := httprouter.New()

    // Add a handler on /test
    r.GET("/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
        // Simply write some test data for now
        fmt.Fprint(w, "Welcome!\n")
    })
    
    //open.Run("https://google.com/")
     
    // open.Start("https://google.com")

    // http://127.0.0.1:3000/test
    // Fire up the server
    http.ListenAndServe("localhost:3000", r)
    fmt.Println("ListenAndServe is blocking")  
    open.RunWith("http://localhost:3000/test", "firefox")  
    fmt.Println("Done")
}

【问题讨论】:

  • 在 Go 中,“阻塞”http.ListenAndServe “非阻塞”:go http.ListenAndServe(...) 并不是很复杂,可能需要一些错误处理。那么究竟是什么问题呢?
  • @Volker:问题是,这是我的第一步,所以我还不是很流利,否则我只会创建一个新线程并休眠几毫秒在打开浏览器之前;目前我还有其他事情要做;)另外,如果 ListenAndServer 是非阻塞的,它会在主程序退出的那一刻退出(AFAIK),这将是立即的。
  • 只需在单独的 go 例程中运行 http.ListenAndServe(),然后休眠一段时间(例如 200 毫秒),然后在浏览器中打开。

标签: http go server


【解决方案1】:

打开监听,启动浏览器,然后进入服务器循环:

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

// The browser can connect now because the listening socket is open.

err := open.Start("http://localhost:3000/test")
if err != nil {
     log.Println(err)
}

// Start the blocking server loop.

log.Fatal(http.Serve(l, r)) 

如另一个答案所示,无需投票。如果在浏览器启动之前打开了监听套接字,浏览器就会连接。

ListenAndServe 是一个方便的函数,它打开一个套接字并调用 Serve。此答案中的代码拆分了这些步骤,因此可以在侦听开始后但在对 Serve 的阻塞调用之前打开浏览器。

【讨论】:

  • 有趣,我喜欢!甚至不需要线程。非常好。
  • 这确实是正确的答案。侦听套接字有一个内部固定大小的积压队列,即使在给定时间没有Accept 正在积极等待,它也可以接受连接。这就是它起作用的原因。
  • server.ListenAndServe 似乎也使用了tcpKeepAliveListener。似乎将套接字的 TCP keepalive 设置为 3 分钟。你也应该这样做。
【解决方案2】:

如果没有错误,http.ListenAndServe() 将永远不会返回。所以你不应该在那之后添加代码,除了处理失败的代码。

你必须启动一个新的 goroutine,所以 ListenAndServe() 在一个 goroutine 中被调用,并且代码检查它是否启动应该在另一个 goroutine 上运行。

您可以通过简单的 HTTP GET 调用来检查您的服务器是否已启动,例如使用 http.Get()

以下示例故意将启动延迟 7 秒。新的 goroutine 启动了一个无休止的 for 循环,检查服务器是否启动,两次尝试之间休眠 1 秒。

例子:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hi!"))
})

go func() {
    for {
        time.Sleep(time.Second)

        log.Println("Checking if started...")
        resp, err := http.Get("http://localhost:8081")
        if err != nil {
            log.Println("Failed:", err)
            continue
        }
        resp.Body.Close()
        if resp.StatusCode != http.StatusOK {
            log.Println("Not OK:", resp.StatusCode)
            continue
        }

        // Reached this point: server is up and running!
        break
    }
    log.Println("SERVER UP AND RUNNING!")
}()

log.Println("Starting server...")
time.Sleep(time.Second * 7)
log.Fatal(http.ListenAndServe(":8081", nil))

示例输出:

2015/09/23 13:53:03 Starting server...
2015/09/23 13:53:04 Checking if started...
2015/09/23 13:53:06 Failed: Get http://localhost:8081: dial tcp [::1]:8081: connectex: No connection could be made because the target machine actively refused it.
2015/09/23 13:53:07 Checking if started...
2015/09/23 13:53:09 Failed: Get http://localhost:8081: dial tcp [::1]:8081: connectex: No connection could be made because the target machine actively refused it.
2015/09/23 13:53:10 Checking if started...
2015/09/23 13:53:10 SERVER UP AND RUNNING!

【讨论】:

    【解决方案3】:

    API 并不是绝对糟糕,但我们只是说“需要一些时间来适应”。以下是在 Server 结构上使用自定义属性的方法:

    s := &http.Server{
        Addr:           cnf.API_SERVER_ADDRESS,
        Handler:        h,
        ReadTimeout:    0, // 1 * time.Minute,
        WriteTimeout:   30 * time.Minute,
        MaxHeaderBytes: 1 << 20,
    }
    
    go func() {
    
        l, err := net.Listen("tcp", cnf.API_SERVER_ADDRESS)
    
        if err != nil {
            log.Fatal(err)
        }
    
        fmt.Println(`{"server_state":"listening"}`)
        log.Fatal(s.Serve(l));
    }()
    

    因为如果你改为使用:

    http.Serve(l, handler)
    

    那么你不能在服务器上定义自定义属性

    【讨论】:

    • 如何关闭服务器?
    猜你喜欢
    • 2013-05-27
    • 2018-12-20
    • 2016-05-24
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多