nginx.conf配置location = /sitemap.txt仍出现404错误求助
问题说明
我在nginx.conf中配置了location = /sitemap.txt { rewrite /.*$ /index.php; }指令,PHP脚本也已准备好处理相关请求,但访问/sitemap.txt时仍收到404错误:The requested resource /sitemap.txt was not found on this server.
原本以为location /的规则已经能处理该请求,为了保险还是添加了上述特定指令。测试确认该location块是生效的——如果替换成return 403;,浏览器会收到403状态码。我不想用静态文件实现,希望通过自动化流程生成站点地图。
完整nginx.conf配置如下:
worker_processes 1; error_log /home/logs/nginx_error.log error; pid /home/tmp/nginx.pid; events { worker_connections 1024; } http { client_max_body_size 19M; client_body_temp_path /home/tmp; proxy_temp_path /home/tmp; fastcgi_temp_path /home/tmp; uwsgi_temp_path /home/tmp; scgi_temp_path /home/tmp; access_log /home/logs/nginx_access.log; include mime.types; default_type application/octet-stream; port_in_redirect on; sendfile on; keepalive_timeout 65; server { listen 8000; server_name www.MYSERVER.COM; charset utf-8; location =/ { absolute_redirect on; port_in_redirect on; server_name_in_redirect on; return 301 http://www.MYSERVER.COM:80/home; } location =/index.php { default_type text/html; proxy_pass http://127.0.0.1:9000$request_uri; proxy_redirect off; include proxy_params; } location /uploads/ { root /home/public; try_files $uri =404; expires 30d; } location / { rewrite ^/(?<pagename>.*)$ /index.php; } location = /sitemap.txt { rewrite /.*$ /index.php; } location /classes/ { deny all; } location /config/ { deny all; } #allow specific files location = /styles.css { root /home/public/resources; } location = /script.js { root /home/public/resources; } location = /robots.txt { root /home/public/resources; } location = /sitemap.xml { root /home/public/resources; } location = /favicon.webp { root /home/public/resources; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/local/www/nginx-dist; } } }
问题原因
Nginx的location匹配遵循精确匹配(location =)优先级最高的规则,所以/sitemap.txt请求会先命中location = /sitemap.txt,但问题出在后续的请求转发环节:
- 当前的
rewrite规则没有指定last或break标记,虽然重写URI为/index.php,但location = /index.php中使用$request_uri作为转发路径——$request_uri是客户端原始请求的URI(即/sitemap.txt),导致PHP服务收到的请求是/sitemap.txt,而非预期的/index.php,如果PHP服务没有配置处理该路径的规则,就会返回404。 - 另外,
location /的规则之所以没生效,是因为精确匹配的优先级高于普通前缀匹配,请求根本不会走到这个块。
解决方案
方案1:调整rewrite规则并修正proxy_pass参数
- 修改
sitemap.txt的location块,添加last标记确保重写后重新匹配location:
location = /sitemap.txt { rewrite ^ /index.php last; }
- 修正
location = /index.php中的proxy_pass,使用$uri(重写后的URI)替代$request_uri:
location =/index.php { default_type text/html; proxy_pass http://127.0.0.1:9000$uri; proxy_redirect off; include proxy_params; }
方案2:直接在sitemap.txt的location块转发到PHP服务
跳过rewrite步骤,直接将请求转发到/index.php,PHP脚本可通过$_SERVER['REQUEST_URI']获取原始请求路径生成对应站点地图:
location = /sitemap.txt { default_type text/html; proxy_pass http://127.0.0.1:9000/index.php; proxy_redirect off; include proxy_params; }
方案3:复用现有location /规则(可选)
如果希望用location /处理所有非静态文件请求,可以删除location = /sitemap.txt的配置,因为location /的rewrite规则本就会匹配/sitemap.txt。但要确保location /的优先级低于其他精确匹配和前缀匹配(比如/uploads/、静态文件的精确匹配),当前配置已经满足这一点。
内容的提问来源于stack exchange,提问作者v010dya

