Назад | Перейти на главную страницу

Go (lang) с nginx - обслуживание статических файлов

В настоящее время у меня есть следующий HTTP-сервер, написанный на 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)
}

Я видел несколько тестов, которые показывают, что nginx может обрабатывать намного больше запросов в секунду, когда дело касается статических файлов. Еще одна полезная функция nginx заключается в том, что он может прозрачно архивировать ответы и даже обслуживать предварительно сжатые файлы с gzip_static модуль.

В идеале я хочу, чтобы nginx обслуживал все существующие (статические) файлы и проксировал все, что не существует, для Go:

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

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

К сожалению, nginx не любит приведенную выше конфигурацию:

nginx: [emerg] «proxy_pass» не может иметь часть URI в местоположении, указанном регулярным выражением, или внутри именованного местоположения, или внутри оператора «if», или внутри блока «limit_except» в / etc / nginx / sites-enabled / default: 23

На данный момент я знаю, что у меня есть несколько вариантов:

1) положить proxy_pass в location / блокировать

Но это проксирует все, даже существующие (статические) файлы.

2) напишите индивиду /json и /socket блоки расположения в nginx

Но если я хочу добавить больше обработчиков в Go, мне также нужно соответственно обновить vhost nginx.

3) перепишите код Go и используйте fastcgi_pass в nginx вместо proxy_pass

location @go {
    fastcgi_pass            127.0.0.1:9000;
}

Мне также пришлось бы изменить код Go, чтобы использовать net/http/fcgi вместо того net/httpпроблема в том, что я не знаю, как указать пути (/json или /socket) с участием fcgi.Serve().

Кроме того, FastCGI кажется в 4 раза медленнее, чем HTTP: https://gist.github.com/hgfischer/7965620.

4) полностью отказаться от nginx

Заставьте Go обслуживать все (включая статические файлы) и обрабатывать сжатие gzip при каждом запросе.


Как заставить nginx и Go вести себя так, как я хочу (желательно с интерфейсом HTTP)?

Приносим извинения, если этот вопрос слишком простой, это мой самый первый опыт написания веб-приложения на Go.

Дополнительный вопрос

В PHP я указываю fastcgi_pass к php-fpm Сокет Unix. Если какой-либо запрос испытывает Неустранимая ошибка PHP, предстоящие запросы по-прежнему будут обслуживаться. Однако, если мой код Go вызывает panic() программа будет завершена, и служба перестанет отвечать. Как лучше всего справиться с этим в Go?

Проблема с "proxy_pass", похоже, связана с трейлингом /, попробуйте удалить его, так как он ничего не делает. Если вам нужно изменить URI перед передачей его прокси, попробуйте использовать перезапись, т.е. чтобы удалить часть URI, попробуйте что-то вроде:

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

Я использовал следующую конфигурацию nginx - ресурс

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

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

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

Ниже представлена ​​моя структура каталогов:

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

В соответствии с этот site Я запускаю простое приложение sinatra:

require 'sinatra'

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

И это ответы

# 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>

Как видите, если файл не существует, запрос отправляется в приложение sinatra.

$ nginx -V
nginx version: nginx/1.2.1