如果在nginx的location块中同时使用limit_except和try_files,会导致出现404 Not Found错误
准备上游
准备一个简单的Sinatra应用程序来响应GET /app和POST /app。
$ rbenv local 2.3.0
$ cat <<EOF > Gemfile
source 'https://rubygems.org'
ruby '2.3.0'
gem 'sinatra'
gem 'thin'
gem 'rack-cors', require: 'rack/cors'
EOF
$ bundle install
$ cat <<EOF > app.rb
require 'sinatra'
get '/app' do
'GET'
end
post '/app' do
'POST'
end
EOF
$ cat <<EOF > config.ru
require './app'
run Sinatra::Application
EOF
$ bundle exec rackup -p 3000
$ curl http://localhost:3000/app
GET
$ curl -X POST http://localhost:3000/app
POST
准备使用try_files指令进行内部重定向。
如果URL路径没有对应的文件,则将其重定向到上游。
$ curl -L -O http://downloads.sourceforge.net/project/pcre/pcre/8.38/pcre-8.38.tar.bz2
$ tar -xjvf pcre-8.38.tar.bz2
$ nginx-build -d . -clear --with-pcre=$(pwd)/pcre-8.38
$ mkdir logs conf
$ cp nginx/1.9.15/nginx-1.9.15/conf/mime.types ./conf
$ cat <<EOF > conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
upstream app {
server localhost:3000;
}
server {
listen 8000;
server_name localhost;
root html;
location / {
try_files $uri $uri/index.html $uri.html @app;
}
location @app {
proxy_pass http://app;
}
}
}
EOF
$ mkdir html
$ echo html > html/index.html
$ ./nginx/1.9.15/nginx-1.9.15/objs/nginx -p $(pwd) -c conf/nginx.conf
$ curl http://localhost:8000/index.html
html
$ curl http://localhost:8000/app
GET
$ curl -X POST http://localhost:8000/app
POST
設置基本認證
在限制条件之前,无论请求方法如何,尝试对所有内容进行基本认证。
$ cp conf/nginx.conf conf/nginx.conf.orig
$ vi conf/nginx.conf
$ diff -u conf/nginx.conf.orig conf/nginx.conf
--- conf/nginx.conf.orig 2016-04-23 16:31:35.000000000 +0900
+++ conf/nginx.conf 2016-04-23 16:48:22.000000000 +0900
@@ -18,6 +18,8 @@
location / {
try_files $uri $uri/index.html $uri.html @app;
+ auth_basic "Basic auth";
+ auth_basic_user_file .htpasswd;
}
location @app {
$ echo "user:$(openssl passwd -apr1 password)" > conf/.htpasswd
$ ./nginx/1.9.15/nginx-1.9.15/objs/nginx -p $(pwd) -c conf/nginx.conf -s reload
$ curl -u 'user:password' http://localhost:8000/app
GET
$ curl -X POST -u 'user:password' http://localhost:8000/app
POST
只允许使用 limit_except 来对 POST 请求进行基本认证。
只有在POST请求方法时才需要进行基本认证。
$ vi conf/nginx.conf
$ diff -u conf/nginx.conf.orig conf/nginx.conf
--- conf/nginx.conf.orig 2016-04-23 16:31:35.000000000 +0900
+++ conf/nginx.conf 2016-04-23 16:51:08.000000000 +0900
@@ -18,6 +18,10 @@
location / {
try_files $uri $uri/index.html $uri.html @app;
+ limit_except GET {
+ auth_basic "Basic auth";
+ auth_basic_user_file .htpasswd;
+ }
}
location @app {
$ ./nginx/1.9.15/nginx-1.9.15/objs/nginx -p $(pwd) -c conf/nginx.conf -s reload
$ curl http://localhost:8000/app
GET
$ curl -i -X POST -u 'user:password' http://localhost:8000/app
HTTP/1.1 404 Not Found
Server: nginx/1.9.15
Date: Sat, 23 Apr 2016 07:51:33 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.9.15</center>
</body>
</html>
404 页面未找到
为什么?
顺便说一下,不管是使用基本身份验证还是与之相关的,只要使用limit_except指令,就会直接返回404 Not Found。
$ vi conf/nginx.conf
$ diff -u conf/nginx.conf.orig conf/nginx.conf
--- conf/nginx.conf.orig 2016-04-23 16:31:35.000000000 +0900
+++ conf/nginx.conf 2016-04-23 16:54:31.000000000 +0900
@@ -18,6 +18,8 @@
location / {
try_files $uri $uri/index.html $uri.html @app;
+ limit_except GET {
+ }
}
location @app {
$ ./nginx/1.9.15/nginx-1.9.15/objs/nginx -p $(pwd) -c conf/nginx.conf -s reload
$ curl http://localhost:8000/app
GET
$ curl -i -X POST -u 'user:password' http://localhost:8000/app
HTTP/1.1 404 Not Found
Server: nginx/1.9.15
Date: Sat, 23 Apr 2016 07:51:33 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.9.15</center>
</body>
</html>
将 “limit_except” 移动到另一个 “location”。
使用limit_except指令在try_files指令的内部重定向位置指令中,便不会返回404 Not Found。
$ vi conf/nginx.conf
$ diff -u conf/nginx.conf.orig conf/nginx.conf
--- conf/nginx.conf.orig 2016-04-23 16:31:35.000000000 +0900
+++ conf/nginx.conf 2016-04-23 16:58:00.000000000 +0900
@@ -21,6 +21,10 @@
}
location @app {
+ limit_except GET {
+ auth_basic "Basic auth";
+ auth_basic_user_file .htpasswd;
+ }
proxy_pass http://app;
}
}
$ ./nginx/1.9.15/nginx-1.9.15/objs/nginx -p $(pwd) -c conf/nginx.conf -s reload
$ curl http://localhost:8000/app
GET
$ curl -X POST -u 'user:password' http://localhost:8000/app
POST
总结
这是怎样的情况呢?
可能是我找文档的方法有问题,找不到相关的说明。
如果阅读源代码的话可能会明白,但是因为觉得麻烦,所以想用一种简单却行得通的方法来应付。