英文:
How can I start the browser AFTER the server started listening?
问题
在Go语言中,你可以在服务器开始监听之后启动浏览器。以下是最简单的方法:
package main
import (
"fmt"
"net/http"
"github.com/skratchdot/open-golang/open"
"github.com/julienschmidt/httprouter"
)
func main() {
// 实例化一个新的路由器
r := httprouter.New()
// 在 /test 上添加一个处理器
r.GET("/test", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
// 现在只是简单地写入一些测试数据
fmt.Fprint(w, "Welcome!\n")
})
// 启动服务器
go func() {
http.ListenAndServe("localhost:3000", r)
}()
// 在服务器启动后打开浏览器
open.RunWith("http://localhost:3000/test", "firefox")
// 阻塞主线程
select {}
}
在这个示例中,我们使用了go
关键字来在一个新的goroutine中启动服务器,这样可以让服务器在后台运行而不阻塞主线程。然后,我们使用open.RunWith
函数在服务器启动后打开浏览器。最后,我们使用select{}
语句来阻塞主线程,以保持程序运行。
请注意,你需要先安装github.com/skratchdot/open-golang
和github.com/julienschmidt/httprouter
这两个包,可以使用go get
命令进行安装。
英文:
In Go, how can I start the browser AFTER the server started listening?
Preferably the simplest way possible.
My code so far, super dumbed down to the point:
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")
}
答案1
得分: 32
打开监听器,启动浏览器,然后进入服务器循环:
l, err := net.Listen("tcp", "localhost:3000")
if err != nil {
log.Fatal(err)
}
// 监听套接字打开后,浏览器可以连接。
err := open.Start("http://localhost:3000/test")
if err != nil {
log.Println(err)
}
// 启动阻塞的服务器循环。
log.Fatal(http.Serve(l, r))
不需要像另一个答案中所示那样进行轮询。如果在启动浏览器之前监听套接字已经打开,浏览器将会连接。
ListenAndServe是一个方便的函数,它打开一个套接字并调用Serve函数。这个答案中的代码将这些步骤分开,以便在监听开始后但在阻塞调用Serve之前打开浏览器。
英文:
Open the listener, start the browser and then enter the server loop:
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))
There's no need to poll as shown in another answer. The browser will connect if the listening socket is open before the browser is started.
ListenAndServe is a convenience function that opens a socket and calls Serve. The code in this answer splits out these steps so the browser can be opened after listening starts but before the blocking call to Serve.
答案2
得分: 14
如果没有错误,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
}
// 到达此点:服务器已启动并运行!
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!
英文:
If there is no error, http.ListenAndServe()
will never return. So you shouldn't add code after that except code that handles failure.
You have to start a new goroutine, so ListenAndServe()
is called in one goroutine, and code checking if it is up should run on the other goroutine.
And you can check if your server is up by making a simple HTTP GET
call to it, for example using http.Get()
.
The following example delays startup for 7 seconds on purpose. The new goroutine starts an endless for
loop that checks if server is up, sleeping 1 second between attempts.
Example:
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))
Example output:
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
得分: 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)
那么你就无法在服务器上定义自定义属性。
英文:
The API is not absolutely terrible, but let's just say "It takes some getting used to". Here is how you use custom attributes on the Server struct:
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));
}()
because if you instead use:
http.Serve(l, handler)
then you can't define custom properties on the server
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论