webdevops nginx - 从 url 中删除 .php 要求

webdevops nginx - remove .php requirement from url

我有一个基于 webdevops/php-nginx:7.2 的 docker,我正在尝试配置 nginx 以将带有或不带有 .php 扩展名的请求路由到适当的文件。

如果 abc.php 存在,我需要 /abc/abc.php 才能路由到 abc.php。其他一切都将转到 index.php

当前设置如下:

Dockerfile 包含

WEB_DOCUMENT_ROOT=/app/public
COPY docker/opt/docker/etc /opt/docker/etc/

opt/docker/etc/nginx/conf.d/10-location-root.conf

server {
  index index.html index.php;
  location / {
    try_files $uri $uri/ /index.php?_url=$uri&$args;
  }
}

/app/public 包含

index.php
abc.php

目前此配置将所有内容路由到 index.php/abc.php 除外。尝试点击 /abcindex.php 的路线。

谢谢:)

编辑: 使用 Ivan 的回答 docker 记录垃圾邮件:

app_1  | -> Executing /opt/docker/bin/service.d/nginx.d//10-init.sh
app_1  | 2020-10-20 10:31:59,273 INFO success: nginxd entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
app_1  | nginx: [emerg] unknown "_uri" variable
app_1  | 2020-10-20 10:31:59,287 INFO exited: nginxd (exit status 1; not expected)

如果我正确理解这个系统是如何工作的,让我们从以下两个文件开始:

  • /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf
location / {
    try_files $uri $uri/ @extensionless-php;
}
location @extensionless-php {
    rewrite ^ $uri.php last;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-php.conf
location ~ \.php$ {
    try_files $uri /<DOCUMENT_INDEX>?_url=$uri&$args;
    fastcgi_pass php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_read_timeout <PHP_TIMEOUT>;
}

以上配置有一处严重缺陷。如果请求的 URI 不是现有 PHP 文件的名称(有或没有 .php 扩展名),$uri 内部 nginx 变量值将始终以 .php 结尾由于 @extensionless-php 命名位置内的 rewrite 规则。这将导致以下结果(假设文件 /app/public/some/path.php 不存在):

/some/path => /index.php?_url=/some/path.php

/some/path.php => /index.php?_url=/some/path.php

要解决此问题,我们可以将原始 $uri 变量值保存在 extensionless-php 命名位置中:

  • /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf
location / {
    try_files $uri $uri/ @extensionless-php;
}
location @extensionless-php {
    set $original_uri $uri;
    rewrite ^ $uri.php last;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-php.conf
location ~ \.php$ {
    try_files $uri /<DOCUMENT_INDEX>?_url=$original_uri&$args;
    fastcgi_pass php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_read_timeout <PHP_TIMEOUT>;
}

这个配置比较好,但还是有瑕疵。如果请求的URI以.php结尾,而/app/public目录下没有相应的PHP文件,则$original_uri变量不会被初始化,_url查询参数将作为空字符串传递给后端:

/some/path => /index.php?_url=/some/path

/some/path.php => /index.php?_url=

对于某些 Web 应用程序来说这可能没问题(空的 _url 查询参数总是意味着无效的路由),但是如果我们想要获得原始 URI,无论它是什么,我们必须做什么?我们可以借助 map 指令(一个 非常 强大的 nginx 特性)来实现它。但是所有 map 块都应该在 server 块之外声明,所以我们需要一个额外的文件:

  • /opt/docker/etc/nginx/conf.d/10-map.conf
map $_uri $original_uri {
    ""          $uri;
    default     $_uri;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-location-root.conf
location / {
    try_files $uri $uri/ @extensionless-php;
}
location @extensionless-php {
    set $_uri $uri;
    rewrite ^ $uri.php last;
}
  • /opt/docker/etc/nginx/vhost.common.d/10-php.conf
location ~ \.php$ {
    try_files $uri /<DOCUMENT_INDEX>?_url=$original_uri&$args;
    fastcgi_pass php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_read_timeout <PHP_TIMEOUT>;
}

这个 map 块意味着 $original_uri 变量将等于 $uri 如果它没有被修改($_uri 变量没有被初始化并且是空的).如果 $_uri 变量不为空,则意味着原始 $uri 已被修改,并且 $_uri 变量现在保持其原始值,因此 $original_uri 变量的值将是设置为 $_uri。此配置应适用于将原始 URI 保留为 _url 查询参数的任何请求。