Golang Goji: both static content and api at the same time

I've been playing with Golang for the past two weeks and can finally get some real work done with apps. It uses static HTML files served by NGINX and the API uses the Goji Web Framework as the backend. I don't use Golang templates because everything is Angular.Js, so static for my needs.

I would like to be able to choose whether to use NGINX for production, or let Go serve static content at the root using the same port the application uses (8000). Thus, the development environment does not require NGINX to be installed.

So tried adding a descriptor to the default multit like this

goji.DefaultMux.Handle("/*", serveStatic)

func serveStatic(w http.ResponseWriter, r *http.Request) {
//http.ServeFile(w, r, r.URL.Path[1:])
http.StripPrefix("/static/", http.FileServer(http.Dir("static")))



This handle is executed immediately after all API paths have been registered (otherwise the API will not work).

I've already tried any combination and either redirects me to HTTP 404 or displays HTML content as text. Nothing good. I wonder if anyone was here and could let me know what I am doing wrong.


While this has nothing to do with my problem, here is the NGINX config I'm using:

server {
listen 80;

# enable gzip compression
    gzip on;
    gzip_min_length  1100;
    gzip_buffers  4 32k;
    gzip_types    text/plain application/x-javascript text/xml text/css;
    gzip_vary on;
# end gzip configuration

location / {
    root /home/mleyzaola/go/src/bitbucket.org/mauleyzaola/goerp/static;
    try_files $uri $uri/ /index.html = 404;

location /api {
    proxy_pass http://localhost:8000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;




source to share

2 answers

I faced similar problems, so maybe the following points will be helpful.

  • Remember to register a handler to serve static content as the destination route. Otherwise, it might fit everyone.

  • Maybe try using absolute paths instead of relative ones.

Here's a simplified version of how my routes are set up with Goji.

func apiExampleHandler(context web.C, resp http.ResponseWriter, req *http.Request) {
    fmt.Fprint(resp, "You've hit the API!")

func main() {
    goji.Handle("/api", apiExampleHandler)

    // Static file handler should generally be the last handler registered. Otherwise, it'll match every path.
    // Be sure to use an absolute path.
    staticFilesLocation := "Some absolute to the directory with your static content."
    goji.Handle("/*", http.FileServer(http.Dir(staticFilesLocation)))





Once you have complete control over your URLs, a simple strategy is to split them at the top level. I use /a

at the beginning of all app urls and /s

at the beginning of all static urls. This makes the installation very easy.

I used Goji for a while and then switched to Gocraft-web. But the principles are the same as URLs will be unambiguous with any structure. Obviously, Gocraft-web does subprogramming; I think Goji can do it too, but it's less obvious. The subroutine helps for several reasons:

  • its a simple way to eliminate ambiguity
  • a router can be faster if its search patterns are simpler.
  • you can separate your code to make it easier to understand.

If you are using static assets in production, you may need to measure it and improve its performance. I find that pre-compressing (gziping) my JS and CSS files can help. I have both uncompressed and compressed versions on the same filesystem and I have a custom static asset bundle that contains the pre-compressed files and serves them for all clients that understand (that's pretty much all browsers). It is also worth examining the expiration date. Both of these ideas are built into Nginx and compile quite easily with little effort.



All Articles