Go (lang) com nginx - Servindo arquivos estáticos

2

Atualmente, tenho o seguinte servidor HTTP escrito em Go:

func main() {
    http.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
        http.ServeFile(response, request, "/var/www/default/htdocs/index.html")
    })

    http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("/var/www/default/htdocs/public"))))

    http.HandleFunc("/json", func(response http.ResponseWriter, request *http.Request) {
        // serves a JSON response
    })

    http.HandleFunc("/socket", func(w http.ResponseWriter, r *http.Request) {
        // replies to the WebSocket
    })

    http.ListenAndServe(":3000", nil)
}

Eu vi alguns benchmarks que mostram que o nginx pode servir muito mais pedidos por segundo quando se trata de arquivos estáticos. Outro recurso útil do nginx é que ele pode compactar as respostas de forma transparente e até mesmo servir arquivos pré-compactados com o módulo gzip_static .

Idealmente, quero que o nginx atenda todos os arquivos (estáticos) existentes e faça proxy de tudo o que não existe para o Go:

location / {
    try_files               $uri $uri/ @go;
}

location @go {
    proxy_pass              http://127.0.0.1:3000/;
    proxy_set_header        Host $host;
}

Infelizmente, o nginx não gosta da configuração acima:

nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/sites-enabled/default:23

Neste ponto, sei que tenho várias opções:

1) coloque proxy_pass no bloco location /

Mas isso fará proxy em tudo, até mesmo nos arquivos existentes (estáticos).

2) escreva blocos de localização /json e /socket individuais em nginx

Mas se eu quiser adicionar mais manipuladores no Go, eu também tenho que atualizar o vnet nginx adequadamente.

3) reescreva o código Go e use fastcgi_pass em nginx em vez de proxy_pass

location @go {
    fastcgi_pass            127.0.0.1:9000;
}

Eu também teria que alterar o código Go para usar net/http/fcgi em vez de net/http , o problema com isso é que eu não sei como especificar os caminhos ( /json ou /socket ) com < href="http://golang.org/src/pkg/net/http/fcgi/child.go?s=6606:6660#L262"> fcgi.Serve() .

Além disso, o FastCGI parece ser 4 vezes mais lento que o HTTP: link .

4) descartar totalmente o nginx

Faça o Go servir tudo (incluindo arquivos estáticos) e manipule a compactação gzip em todas as solicitações.

Como posso fazer o nginx e o Go para se comportar como eu quero (de preferência com a interface HTTP)?

Desculpas se esta pergunta for demasiado básica, esta é a minha primeira experiência a escrever uma aplicação Web Go.

Pergunta adicional

No PHP, eu aponto fastcgi_pass para o soquete php-fpm Unix. Se qualquer solicitação tiver um erro fatal do PHP , as próximas solicitações ainda serão exibidas. No entanto, se meu Go code chamar panic() , o programa será encerrado e o serviço parará de responder. Qual é a melhor maneira de lidar com isso no Go?

    
por Alix Axel 26.03.2014 / 22:23

2 respostas

4

O problema com o "proxy_pass" parece ser devido ao trailing / , tente removê-lo, já que ele não faz nada. Se você precisar alterar o URI antes de passá-lo para o proxy, tente usar a reescrita, ou seja, para remover alguma parte do URI, tente algo como:

location @go {
    rewrite           ^/part_to_remove(/.*)$ $1;
    proxy_pass        http://127.0.0.1:3000;
    proxy_set_header  Host $host;
}
    
por 27.03.2014 / 02:49
2

Eu usei a seguinte configuração do nginx - resource

server {
  server_name _;
  root /home/vagrant/htdocs/sinatra-test;

  location / {
    try_files $uri $uri/ @backend;
  }

  location @backend {
    proxy_pass http://localhost:4567;
  }
}

Abaixo está minha estrutura de diretórios:

/home/vagrant/htdocs/sinatra-test
|-- Gemfile
|-- Gemfile.lock
|-- app.rb
'-- assets
    '-- css
        '-- screen.css

De acordo com este site eu corro um aplicativo sinatra simples:

require 'sinatra'

get '/hi' do
  "Hello World!"
end

E essas são as respostas

# logged in the sinatra log
$ curl localhost/hi
Hello World!

# not logged in the sinatra log - comes directly from nginx
$ curl localhost/assets/css/screen.css
body { background: red; }

# logged in the sinatra log
$ curl localhost/test
<!DOCTYPE html>
<html>
<head>
  <style type="text/css">
  body { text-align:center;font-family:helvetica,arial;font-size:22px;
    color:#888;margin:20px}
  #c {margin:0 auto;width:500px;text-align:left}
  </style>
</head>
<body>
  <h2>Sinatra doesn&rsquo;t know this ditty.</h2>
  <img src='http://localhost:4567/__sinatra__/404.png'>
  <div id="c">
    Try this:
    <pre>get '/test' do
  "Hello World"
end
</pre>
  </div>
</body>
</html>

Como você pode ver se o arquivo não existe, o pedido vai para o aplicativo sinatra.

$ nginx -V
nginx version: nginx/1.2.1
    
por 27.03.2014 / 00:47

Tags