【问题标题】:Rewriting all URLs to a single PHP controller on nginx将所有 URL 重写到 nginx 上的单个 PHP 控制器
【发布时间】:2022-01-14 03:56:56
【问题描述】:

我有一个 Web 服务器,它有两个 PHP 文件,index.phpcontroller.php,后者使用 p(用于页面)参数处理所有非 / 请求,例如

/controller.php?p=some_page

以下 nginx 配置运行良好:

server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /code;
    
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

但是,我现在想清理 URL,并希望 / 转到 index.php/some_page 转到 /controller.php?p=some_page

这是我正在尝试的新配置:

server {
    listen 80;
    index index.php index.html;
    server_name localhost;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /code;

    # this is new, and makes index.php handle /
    location / {
        index index.php;
        try_files $uri $uri/ =404;
    }
    
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    # this is new, but doesn't work.
    location @rewrites {
        if ($uri ~* ^/([0-9a-z_]+)$) {
            set $page_to_view "/controller.php?p=$1";
            rewrite ^/([0-9a-z_]+)$ $scheme://$http_host/controller.php?p=$1 last;
        }
    }
}

浏览器地址栏显示如下:

- http://localhost:8080/some_page                  (initial request)
- http://localhost:8080/controller.php?p=some_page (first redirect one second later)
- https://localhost/some_page/                      (final redirect another second later)

因此,它最终出现在一个没有原始端口的 URL 上,带有一个斜杠,并使用方案 https

我能做些什么来解决它?

PS 如果尾部斜杠无关紧要(即localhost:8080/some_pagelocalhost:8080/some_page/ 显示相同的内容。

PS 8080 端口只是我通过 Docker 在本地测试,它将容器 80 映射到主机 8080。

更新:

我已经实现了 Richard 的答案,并尝试了建议的 curl

$ curl -I http://localhost:8080/some_page
HTTP/1.1 301 Moved Permanently
Server: nginx/1.21.4
Date: Thu, 09 Dec 2021 15:07:11 GMT
Content-Type: text/html
Content-Length: 169
Location: http://localhost/some_page/
Connection: keep-alive

请注意缺少 8080 端口。

更新 2:

使用 nginx 指令absolute_redirect off;,我得到了这个:


$ curl -I http://localhost:8080/some_page
HTTP/1.1 301 Moved Permanently
Server: nginx/1.21.4
Date: Thu, 09 Dec 2021 16:01:31 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: /some_page/

$ curl -I http://localhost:8080/some_page/
HTTP/1.1 404 Not Found
Server: nginx/1.21.4
Date: Thu, 09 Dec 2021 16:01:34 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive

所以,问题仍然是对/some_page/ 的请求如何提供来自/controller.php?p=some_page 的响应

【问题讨论】:

    标签: docker nginx


    【解决方案1】:

    命名位置(例如location @rewrites)通常从try_files 语句的最后一个元素调用。

    例如:

    location / {
        index index.php;
        try_files $uri $uri/ @rewrites;
    }
    

    在您的 location @rewrites 块中,if 语句是不必要的,set 变量未使用,rewrite 语句将引发外部重定向。

    试试:

    location @rewrites {
        rewrite ^/([0-9a-z_]+)$ /controller.php?p=$1 last;
    }
    

    【讨论】:

    • 谢谢,理查德。我尝试了一些建议,但现在就被禁止了。在github.com/juanuys/fake-presskit 的repro repo 但将controller.php 改为sheet.php,所以试试localhost:8080/sheet.php?p=a_night_at_locke_manorlocalhost:8080/a_night_at_locke_manor
    • 很遗憾,您仍然有两个错误。 @rewrites 必须是try_files 语句的last 元素,如果您想要内部重定向,则需要从rewrite 语句中删除$scheme://$http_host
    • 不幸的是,它仍然出现在我上面帖子的第三个链接上 (localhost/some_page)。这是包含您的建议的版本:github.com/juanuys/fake-presskit/blob/master/…
    • 使用curl -I http://localhost:8080/controller.php?p=some_page 查看服务器实际返回的内容。也许您的控制器正在生成最终的重定向。
    • 我重定向到http://localhost/some_page/,它没有端口和一个斜杠。我已经用一个非常简单的 controller.php 更新了 repo 以进行测试,以消除不可靠的代码。
    【解决方案2】:

    我已经找到了一个可以使用原始链接的配置,也可以使用我想要的漂亮 URL。

    server {
        listen 80;
        index index.php;
        server_name localhost;
        error_log  /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
        root /code;
    
        location = / {
            index index.php;
            try_files $uri $uri/ =404;
        }
    
        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass php:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }
    
        location ~* {
            rewrite ^/([0-9a-z_]+)/?$ /controller.php?p=$1 last;
        }
    }
    

    关键似乎是不使用命名位置进行重写,但如果请求不是针对 / 或 PHP 文件,则只需将“其他所有内容”与 location ~* 匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-02
      • 2021-11-26
      • 2016-08-09
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      相关资源
      最近更新 更多