Go(lang) 与 nginx - 提供静态文件

Go(lang) 与 nginx - 提供静态文件

目前我有以下用 Go 编写的 HTTP 服务器:

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 压缩,甚至可以使用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”不能在正则表达式给出的位置、命名位置内、“if”语句内或 /etc/nginx/sites-enabled/default:23 中的“limit_except”块内有 URI 部分

此时,我知道我有几个选择:

1)放入块proxy_passlocation /

但这将代理所有内容,甚至是现有的(静态)文件。

2)在 nginx 中写入单独的/json/socket位置块

但是如果我想在 Go 中添加更多处理程序,我还必须相应地更新 nginx vhost。

3)重写 Go 代码并fastcgi_pass在 nginx 中使用,而不是proxy_pass

location @go {
    fastcgi_pass            127.0.0.1:9000;
}

我还必须更改 Go 代码以使用net/http/fcginet/http问题是我不知道如何使用指定路径(/json/socketfcgi.Serve()

此外,FastCGI 似乎比 HTTP 慢 4 倍:https://gist.github.com/hgfischer/7965620

4)彻底抛弃 nginx

让 Go 为所有内容(包括静态文件)提供服务,并处理每个请求的 gzip 压缩。


我怎样才能让 nginx 和 Go 按照我想要的方式运行(最好使用 HTTP 接口)?

如果这个问题太基础,请原谅,这是我第一次编写 Go 网络应用程序。

附加问题

在 PHP 中,我指向fastcgi_passUnixphp-fpm套接字。如果任何请求遇到PHP 致命错误,即将到来的请求仍将得到服务。但是,如果我的 Go 代码调用,panic()程序将终止,服务将停止响应。在 Go 中处理这种情况的最佳方法是什么?

答案1

“proxy_pass” 的问题似乎是由于尾随的/,请尝试将其删除,因为它无论如何都不起作用。如果您需要在将 URI 传递给代理之前更改它,请尝试使用重写,即删除 URI 的某些部分,请尝试以下操作:

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

答案2

我使用了以下 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

根据我运行了一个简单的 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

相关内容