В настоящее время у меня есть следующий 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’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