在运行时由第三方模块向ngx_http_fastcgi_module注入自定义变量
我正在编写一个第三方的C 语言NGINX模块。
我想实现类似Apache模块mod_env的功能:
SetEnv MY_VAR hello
在正常的NGINX配置中,这样就能工作:
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param MY_VAR "hello";
}
那么PHP-FPM就可以读取:
$_SERVER['MY_VAR']
我的问题是:
一个第三方的NGINX模块能否在请求运行时动态添加一个新的fastcgi_param,既不对ngx_http_fastcgi_module进行补丁,也不在nginx.conf的 fastcgi_param中写入该变量?
解决方案
不行,纯请求运行时不能对任意FastCGI参数名进行动态添加。
"ngx_http_fastcgi_module" 会在内部构建FastCGI PARAMS记录
"ngx_http_fastcgi_create_request()"。
如果某个参数名尚未被FastCGI模块所认知,其他第三方模块就无法在运行时干净地添加它,例如MY_VAR=hello,除非对ngx_http_fastcgi_module.c进行补丁或替换。
有两种实际可行的替代方案。
1.使用 r->headers_in 为 HTTP_* 参数
在 ngx_http_fastcgi_module.c 中,注意这个函数:
ngx_http_fastcgi_create_request()
在该函数内部,NGINX从以下位置读取请求头:
r->headers_in
并将它们转换为FastCGI参数,使用以下模式:
HTTP_ + uppercase(header name, with "-" changed to "_")
例如:
curl -H "Authorization: Bearer testtoken123" http://example.com/
在PHP中可以显示为:
$_SERVER["HTTP_AUTHORIZATION"]
因为FastCGI会将请求头转换成如下形式:
Authorization -> HTTP_AUTHORIZATION
X-My-Var -> HTTP_X_MY_VAR
User-Agent -> HTTP_USER_AGENT
因此,在 ngx_http_fastcgi_create_request() 运行之前,第三方模块可以添加或修改请求头。
限制是这只能提供 HTTP_* 参数名,而不是任意名称,例如 MY_VAR。
2.使用带有动态NGINX变量值的生成include文件
在 nginx.conf 中保留一个静态include:
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
include /path/generated_fastcgi_params.conf;
}
自动生成该文件:
fastcgi_param MY_VAR $my_var;
fastcgi_param APP_ENV $app_env;
然后你的模块可以在请求运行时动态设置 $my_var 和 $app_env 的值。
因此最终的规则是:
FastCGI param names must exist before ngx_http_fastcgi_create_request() runs.
FastCGI param values can be dynamic set in run time handler.
这让行为类似于Apache的 mod_env / SetEnv,无需对 ngx_http_fastcgi_module 进行补丁,但新参数名需要先在nginx.conf的 include文件中设定好,你可以在配置阶段通过conf缓冲区等进行动态注入。