Go:如何在服务器开始收听后启动浏览器?

时间:2015-09-23 11:20:15

标签: http go server

在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")
}

3 个答案:

答案 0 :(得分:16)

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

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之前打开浏览器。

答案 1 :(得分:13)

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

你必须开始一个新的goroutine,所以在一个goroutine中调用ListenAndServe(),并且代码检查它是否应该在另一个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!

答案 2 :(得分:0)

该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)

那么您将无法在服务器上定义自定义属性