nginx + fcgiwrap:fastcgi_param的顺序如何?

我正在运行Debian 6.0.3squeeze ), nginx-0.7.67fcgiwrap-1.0-1+squeeze1 。 这里是testing脚本:

 #!/usr/bin/perl use 5.010; use warnings; use strict; use Data::Dumper; print "Content-Type: text/html\n\n"; say Dumper {map {$_ => $ENV{$_}} 'SCRIPT_NAME', 'DOCUMENT_ROOT', 'WHATEVER'}; say "$<, $>, $(, $)"; 

这里是nginxconfiguration:

 server { server_name domain.com; root /home/yuri/6; access_log /var/log/nginx/domain.com-access.log; error_log /var/log/nginx/domain.com-error.log; location /cgi-bin/ { fastcgi_pass unix:/var/run/fcgiwrap.socket; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param DOCUMENT_ROOT /home/yuri/7/; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param WHATEVER 1; fastcgi_param WHATEVER 2; } location /1.php { fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_param PHP_ADMIN_VALUE cgi.fix_pathinfo=1; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME whatever; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } } 

这是我得到的浏览器如果去http://domain.com/cgi-bin/1.pl :

 $VAR1 = { 'SCRIPT_NAME' => '/cgi-bin/1.pl', 'DOCUMENT_ROOT' => '/home/yuri/7/', 'WHATEVER' => '2' }; 

所以看来, fcgiwrap使用第一个DOCUMENT_ROOT来查找脚本,但脚本获取了params的最后一个值。 如果您更改DOCUMENT_ROOT指令的顺序,则Web服务器返回403 。 问题是…怎么回事?

php虽然按预期工作:第二个SCRIPT_FILENAME覆盖第一个。

fastcgi库只是传递给它的任何参数到environ指针中。 getenv()用于fcgiwrap使用任何环境variables先来(优化?)。 PHP FPM很可能就像数组数据types一样处理这个环境,后面的任何键都会覆盖第一个。

你不应该依赖订单,并确保只有一个关键。 我没有看过FastCGI规范,是否logging了正确的行为。

至于你为什么得到403,我想没有/home/yuri/7/1.pl文件。 (请记住,第一个参数由fcgiwrap匹配)。 由于它不可执行,fcgiwrap返回一个403。

testing

下面的补丁打印FCGI_Accept()给出的环境:

 diff --git a/fcgiwrap.cb/fcgiwrap.c index e86ff9d..0dff2e6 100644 --- a/fcgiwrap.c +++ b/fcgiwrap.c @@ -470,6 +470,11 @@ static void inherit_environment(void) char * const * p; char *q; + for (p = environ; *p; p++) + fprintf(stderr, "ENV: %s\n", *p); + + fprintf(stderr, "ENV[FOO] = %s\n", getenv("FOO")); + for (p = inherited_environ; *p; p++) { q = strchr(*p, '='); if (!q) { 

用于testing的nginxconfiguration:

 events { worker_connections 768; } pid pid; error_log error_log; http { server { access_log off; listen 5555; location / { fastcgi_param FOO BAR; fastcgi_param FOO BARRED; fastcgi_pass unix:/tmp/sock; } } } 

启动服务器的命令(假设当前目录下有nginx.conf ):

 $ nginx -p . -c nginx.conf $ env -i ./fcgiwrap -p /dev/null -s unix:/tmp/sock 

现在运行curl http://localhost:5555/ ,stderr会打印:

 ENV: FCGI_ROLE=RESPONDER ENV: FOO=BAR ENV: FOO=BARRED ENV: HTTP_USER_AGENT=curl/7.30.0 ENV: HTTP_HOST=localhost:5555 ENV: HTTP_ACCEPT=*/* ENV[FOO] = BAR Cannot get script name, are DOCUMENT_ROOT and SCRIPT_NAME (or SCRIPT_FILENAME) set and is the script executable? 

除此之外,这是一个开发版本。 当前的stable(1.1.0)不包含上面的-p参数。 对于结果它并不重要,你也可以放弃它,并收到一个错误,没有给出SCRIPT_NAME或什么。