nginx fastcgi 在文件不存在时返回自己的 404 响应而不是 PHP 的 No input file specified.,是很有必要的。因为 “No input file specified.”真正的意思是没有找到文件,也就是说文件不存在,而不是“没有指定要处理的脚本文件”。文件不存在就应该给出 404 响应,但“No input file specified.”的响应状态码是 200,这会让人困惑。要实现 nginx 接管 404 响应,有几个方法。
方法一、配置 nginx 劫持 fast CGI 程序的错误- fastcgi_intercept_errors on;
复制代码 这能在 PHP 找不到脚本文件时将 404 错误交给 nginx 处理,但会导致设置状态为 4xx、5xx 等数值的脚本中的响应体被 nginx 吞掉。
方法二、在处理 PHP 的 location 配置块中使用 try_files- try_files $uri $uri/ =404;
复制代码 这能在 PHP 找不到脚本文件时将 404 错误交给 nginx 处理,但会导致有 PATH INFO 的 URL 直接被判定为文件不存在。
比如访问 /index.php/wuxiancheng.cn/robots.txt 时,虽然 index.php 存在,但由于 nginx 测试的是完整的 $uri,最终的判定结果是文件 robots.txt 不存在。
方法三、先测试文件是否存在,再交给 PHP 处理。
在处理 PHP 的 location 配置块中添加- if (!-f $document_root$fastcgi_script_name) {
- return 404;
- }
复制代码 这样配置有一个暗坑:如果受访问的资源是一个目录,nginx 也会返回 404。这种场景下,实际上应该报 403 而不是 404 或 200。因此还要加一个判断文件夹的逻辑。- if (-d $document_root$fastcgi_script_name) {
- return 403;
- }
- if (!-f $document_root$fastcgi_script_name) {
- return 404;
- }
复制代码 要正确处理 PATH INFO,还要分割脚本文件和 PATH INFO。综合配置如下。- location ~* "[^/]\.php(/|$)" {
- fastcgi_split_path_info "^(.*\.php)(/.*)?$";
- if (-d $document_root$fastcgi_script_name) {
- return 403;
- }
- if (!-f $document_root$fastcgi_script_name) {
- return 404;
- }
-
- fastcgi_connect_timeout 5;
- fastcgi_intercept_errors off;
- fastcgi_index index.php;
- fastcgi_max_temp_file_size 2047m;
- fastcgi_read_timeout 86400;
- fastcgi_send_timeout 86400;
- fastcgi_pass 127.0.0.1:10018;
-
- fastcgi_param PATH_INFO $fastcgi_path_info;
- fastcgi_param QUERY_STRING $query_string;
- fastcgi_param REQUEST_METHOD $request_method;
- fastcgi_param CONTENT_TYPE $content_type;
- fastcgi_param CONTENT_LENGTH $content_length;
- fastcgi_param SCRIPT_NAME $fastcgi_script_name;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- fastcgi_param REQUEST_URI $request_uri;
- fastcgi_param DOCUMENT_URI $document_uri;
- fastcgi_param DOCUMENT_ROOT $document_root;
- fastcgi_param SERVER_PROTOCOL $server_protocol;
- fastcgi_param REQUEST_SCHEME $scheme;
- fastcgi_param HTTPS $https if_not_empty;
- fastcgi_param GATEWAY_INTERFACE CGI/1.1;
- fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
- fastcgi_param REMOTE_ADDR $remote_addr;
- fastcgi_param REMOTE_PORT $remote_port;
- fastcgi_param SERVER_ADDR $server_addr;
- fastcgi_param SERVER_PORT $server_port;
- fastcgi_param SERVER_NAME $server_name;
- }
复制代码 这样配置,实际上仍然存在问题:当一个文件夹叫 wuxiancheng.php,看名字它是 php 脚本文件,而实际上它是目录时,它会被意外当成 php 文件处理而无法作为目录处理。这个问题的解决办法见另外一篇文章:nginx fastcgi php 遇到名字以 .php 结尾的目录时无法正常访问的解决办法。 |
|