我试图让Nginx为我的认证管理员用户提供一些PHP静态文件。这很有效,我拿回了文件。但是它的状态码是404。
我使用以下(Symfony/Silex) php代码:
use SymfonyComponentHttpFoundationBinaryFileResponse;
use SymfonyComponentHttpFoundationResponseHeaderBag;
$filePath = '/usr/share/nginx/project/src/path/to/my/protected/static/dir/' . $file;
if (empty($file) || !is_readable($filePath)) {
$app->abort(404);
}
$response = new BinaryFileResponse($filePath);
$response->trustXSendfileTypeHeader();
$response->setPrivate();
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_INLINE,
$file,
iconv('UTF-8', 'ASCII//TRANSLIT', $file)
);
$response->headers->addCacheControlDirective('must-revalidate', true);
return $response;
下面是我的nginx配置:
server {
listen 443;
listen [::]:443;
root /usr/share/nginx/project/web;
index index.php;
error_page 401 403 404 /404.html;
server_name example.com;
rewrite ^/(.*)/$ /$1 permanent;
location / {
# First attempt to serve request as file, then
# as directory, then let php handle the file
try_files $uri $uri/ /index.php$is_args$args;
index index.php;
autoindex off;
location ~* .(svg|jpg|jpeg|png|gif|ico|css|js)$ {
expires 150d;
}
}
location ~ .php$ {
set $path_info $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+.php)(/.*)$;
try_files $uri $uri/ /index.php$is_args$args;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
include fastcgi_params;
fastcgi_param APP_ENV production;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
受保护的目录位于nginx配置(/usr/share/nginx/project/web
)的根目录之外。
我在日志中发现了这些错误信息:
open() "/usr/share/nginx/project/web/admin/static/admin.js" failed
(2: No such file or directory),
request: "GET /admin/static/admin.js HTTP/1.1"
其中/admin/static/admin.js
确实是请求的url。
更新1
看起来nginx总是试图打开url并在错误日志中添加一个条目,即使php处理响应很好。
即使我替换所有的php代码只是:return new Response('test', 200);
的响应代码的身体'测试'仍然是404…
我还尝试在我的nginx配置中添加一个额外的位置块:
location /protected_admin_files {
internal;
alias /usr/share/nginx/project/src/path/to/my/protected/static/dir;
}
然后尝试重定向到文件,像这样:
return new Response('', 200, [
'X-Accel-Redirect' => '/protected_admin_files/' . $file
]);
但也没有运气。相同的404与正确的响应体…
我自己找到了原因。
这是我在错误日志中发现的,一旦我将错误级别设置为debug
(这里是完整的日志)
...
[debug] rewrite phase: 1
[debug] http script regex: "^/(.*)/$"
[notice] "^/(.*)/$" does not match "/admin/static/admin.js", request: "GET /admin/static/admin.js HTTP/1.1", host: "example.com"
[debug] test location: "/"
[debug] test location: "protected_admin_files"
[debug] test location: ~ ".(svg|jpg|jpeg|png|gif|ico|css|js)$"
[debug] using configuration ".(svg|jpg|jpeg|png|gif|ico|css|js)$"
...
[debug] http filename: "/usr/share/nginx/project/web/admin/static/admin.js"
[debug] add cleanup: 00000000025AE108
[error] open() "/usr/share/nginx/project/web/admin/static/admin.js" failed (2: No such file or directory), client: 24.132.134.203, server: example.com, request: "GET /admin/static/admin.js HTTP/1.1", host: "example.com"
[debug] http finalize request: 404, "/admin/static/admin.js?" a:1, c:1
[debug] http special response: 404, "/admin/static/admin.js?"
[debug] internal redirect: "/index.php?"
...
显然,嵌套的location
在我的第一个location /
块是导致404。
location / {
try_files $uri $uri/ /index.php$is_args$args;
index index.php;
autoindex off;
location ~* .(svg|jpg|jpeg|png|gif|ico|css|js)$ {
expires 150d;
}
}
因为扩展名匹配,使得Nginx去寻找文件。因为它没有被找到,所以404被设置,并且在php返回X-Accel-Redirect标头时显然不会被覆盖。