Ciasto piekarz
Ciasto piekarz

Reputation: 8277

How start web server to open page in browser in golang?

How do I temporarily open a web page in browser using golang?

Like here is how it is done using HTTPServer in python.

Upvotes: 18

Views: 27794

Answers (5)

Javad
Javad

Reputation: 223

for windows simply run:

exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Run()

Upvotes: 0

icza
icza

Reputation: 418377

Your question is a little misleading as it asks how to open a local page in the web browser, but you actually want to know how to fire up a web server so it can be opened in the browser.

For the latter (firing up a web server to serve static files), you may use the http.FileServer() function. For answers presenting it in greater detail, see: Include js file in Go template and With golang webserver where does the root of the website map onto the filesystem>.

Example serving your /tmp/data folder:

http.Handle("/", http.FileServer(http.Dir("/tmp/data")))
panic(http.ListenAndServe(":8080", nil))

If you want to serve dynamic content (generated by Go code), you can use the net/http package and write your own handler generating the response, e.g.:

func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello from Go")
}

func main() {
    http.HandleFunc("/", myHandler)
    panic(http.ListenAndServe(":8080", nil))
}

As to the first (to open a page in your default browser), there is no builtin support in the Go standard library. But it's not that hard, you just have to execute an OS-specific external command. You may use this cross-platform solution (which I also released in my github.com/icza/gox library, see osx.OpenDefault()):

// open opens the specified URL in the default browser of the user.
func open(url string) error {
    var cmd string
    var args []string

    switch runtime.GOOS {
    case "windows":
        cmd = "cmd"
        args = []string{"/c", "start"}
    case "darwin":
        cmd = "open"
    default: // "linux", "freebsd", "openbsd", "netbsd"
        cmd = "xdg-open"
    }
    args = append(args, url)
    return exec.Command(cmd, args...).Start()
}

This example code is taken from Gowut (which is Go Web UI Toolkit; disclosure: I'm the author).

Note that exec.Command() performs OS-specific argument quoting if needed. So for example if the URL contains &, it will be properly escaped on Linux, however, it might not work on Windows. On Windows you might have to manually quote it yourself, e.g. with replacing & signs with "^&" with a call like strings.ReplaceAll(url, "&", "^&").

Using this to open the previously started webserver in your default browser:

open("http://localhost:8080/")

One last thing to note: http.ListenAndServe() blocks and never returns (if there is no error). So you have to start the server or the browser in another goroutine, for example:

go open("http://localhost:8080/")
panic(http.ListenAndServe(":8080", nil))

Check out this question for other alternatives how to start the browser after the webserver has been started: Go: How can I start the browser AFTER the server started listening?

Upvotes: 42

Sebastian
Sebastian

Reputation: 1853

Building off of Paul's answer, here is a solution that works on Windows:

package main

import (
    "log"
    "net/http"
    "os/exec"
    "time"
)


func main() {
    http.HandleFunc("/", myHandler)
    go func() {
        <-time.After(100 * time.Millisecond)
        err := exec.Command("explorer", "http://127.0.0.1:8080").Run()
        if err != nil {
            log.Println(err)
        }
    }()

    log.Println("running at port localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Upvotes: 0

Paul Buis
Paul Buis

Reputation: 815

Last time I did something like this, I added a short delay before starting up the browser, to make sure the server had time to be listening before the browser sent the first request. On my Linux system, xdg wasn't configured quite right and rather than fixing the xdg configuration, I just hardwired it with "firefox" rather than "xdg-open". Starting the browser on the same machine as the web server made for a good thing in development. But in deployment, the web server is likely to be running on a headless remote system and it might make more sense to simply print the initial URL to the console for a copy-paste from a terminal session to the remote server into a local browser.

package main

import (
    "fmt"
    "net/http"
    "time"
)

func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "Hello from Go")
}

func main() {
    http.HandleFunc("/", myHandler)
    go func() {
        <-time.After(100 * time.Millisecond)
        open("http://localhost:8080/")
    }()
    panic(http.ListenAndServe(":8080", nil))
}

Upvotes: -1

Grzegorz Żur
Grzegorz Żur

Reputation: 49231

It is quite a general problem. You can use xdg-open program to do it for you. Just run the process from Go. The xdg-open will fork by itself so we can just simply use Run and wait for the end of process.

package main

import "os/exec"

func main() {
    exec.Command("xdg-open", "http://example.com/").Run()
}

Upvotes: 1

Related Questions