httpbrowsergoserver

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.


Solution

  • 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()):

    // openURL opens the specified URL in the default browser of the user.
    func openURL(url string) error {
        var cmd string
        var args []string
    
        switch runtime.GOOS {
        case "windows":
            cmd = "cmd"
            args = []string{"/c", "start"}
        case "darwin":
            cmd = "open"
                    args = []string{url}
        default: // "linux", "freebsd", "openbsd", "netbsd"
            // Check if running under WSL
            if isWSL() {
                // Use 'cmd.exe /c start' to open the URL in the default Windows browser
                cmd = "cmd.exe"
                args = []string{"/c", "start", url}
            } else {
                // Use xdg-open on native Linux environments
                cmd = "xdg-open"
                args = []string{url}
            }
        }
        if len(args) > 1 {
            // args[0] is used for 'start' command argument, to prevent issues with URLs starting with a quote
            args = append(args[:1], append([]string{""}, args[1:]...)...)
        }
        return exec.Command(cmd, args...).Start()
    }
    
    // isWSL checks if the Go program is running inside Windows Subsystem for Linux
    func isWSL() bool {
        releaseData, err := exec.Command("uname", "-r").Output()
        if err != nil {
            return false
        }
        return strings.Contains(strings.ToLower(string(releaseData)), "microsoft")
    }
    

    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: How can I start the browser AFTER the server started listening?