You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派4B中Nginx+fastcgi_wrap环境下C CGI无法将QUERY_STRING解析到argv[]

C CGI程序在Nginx+fastcgi_wrap环境下QUERY_STRING无法传入argv[]的问题

我是树莓派4B上的C CGI开发新手,用Nginx + fastcgi_wrap + spawn-cgi做练习,跟着《C Programming in Linux》第16页的内容操作。命令行直接运行程序时,QUERY_STRING能正常传到main函数的argv[]里,输出符合预期;但通过浏览器或curl访问时,QUERY_STRING没法传到argv[],只能用getenv获取到值。而在Apache环境下运行这个程序,QUERY_STRING能正常传入argv[]。下面是我的C代码、Nginx配置及相关运行输出,求帮忙排查。

命令行运行输出

$ ./hello3 my first Cproc
Content-type:text/plain

Hello, you are still learning C!!
Number of arguments to the main function: 4
arguments number 0 is ./hello3
arguments number 1 is my
arguments number 2 is first
arguments number 3 is Cproc
QUERY_STRING got by getenv: (null);
env[0]=SHELL=/bin/bash
env[1]=LANGUAGE=en_US.UTF-8
env[2]=NO_AT_BRIDGE=1
env[3]=PWD=/var/www/html/cgi-bin
env[4]=LOGNAME=pi
env[5]=XDG_SESSION_TYPE=tty
env[6]=HOME=/home/pi
env[7]=LANG=en_US.UTF-8
env[8]=LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
env[9]=SSH_CONNECTION=192.168.1.62 2295 192.168.1.118 22
env[10]=XDG_SESSION_CLASS=user
env[11]=TERM=xterm
env[12]=USER=pi
env[13]=DISPLAY=localhost:10.0
env[14]=SHLVL=1
env[15]=XDG_SESSION_ID=4
env[16]=XDG_RUNTIME_DIR=/run/user/1000
env[17]=SSH_CLIENT=192.168.1.62 2295 22
env[18]=LC_ALL=en_US.UTF-8
env[19]=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
env[20]=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
env[21]=MAIL=/var/mail/pi
env[22]=SSH_TTY=/dev/pts/0
env[23]=OLDPWD=/home/pi
env[24]=TEXTDOMAIN=Linux-PAM
env[25]=_=./hello3

curl访问输出

$ curl -i http://192.168.1.118/cgi-bin/hello3?my+first+Cproc
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 28 Jul 2022 03:33:15 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
Connection: keep-alive

Hello, you are still learning C!!
Number of arguments to the main function: 1
arguments number 0 is /var/www/html/cgi-bin/hello3
QUERY_STRING got by getenv: my+first+Cproc;
env[0]=FCGI_ROLE=RESPONDER
env[1]=SCRIPT_FILENAME=/var/www/html/cgi-bin/hello3
env[2]=QUERY_STRING=my+first+Cproc
env[3]=REQUEST_METHOD=GET
env[4]=CONTENT_TYPE=
env[5]=CONTENT_LENGTH=
env[6]=SCRIPT_NAME=/cgi-bin/hello3
env[7]=REQUEST_URI=/cgi-bin/hello3?my+first+Cproc
env[8]=DOCUMENT_URI=/cgi-bin/hello3
env[9]=DOCUMENT_ROOT=/var/www/html
env[10]=SERVER_PROTOCOL=HTTP/1.1
env[11]=REQUEST_SCHEME=http
env[12]=GATEWAY_INTERFACE=CGI/1.1
env[13]=SERVER_SOFTWARE=nginx/1.14.2
env[14]=REMOTE_ADDR=192.168.1.118
env[15]=REMOTE_PORT=56758
env[16]=SERVER_ADDR=192.168.1.118
env[17]=SERVER_PORT=80
env[18]=SERVER_NAME=_
env[19]=REDIRECT_STATUS=200
env[20]=HTTP_HOST=192.168.1.118
env[21]=HTTP_USER_AGENT=curl/7.64.0
env[22]=HTTP_ACCEPT=*/*
env[23]=LANG=en_US.UTF-8
env[24]=LANGUAGE=en_US.UTF-8
env[25]=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
env[26]=HOME=/var/www
env[27]=LOGNAME=www-data
env[28]=USER=www-data
env[29]=INVOCATION_ID=99694992abd040ac81d526dddaa66988
env[30]=JOURNAL_STREAM=9:27356
env[31]=DAEMON_OPTS=-f

C代码

/*C code in …www/cgi-bin/*/
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[], char *env[])
{
        int i=0;
        printf("Content-type:text/plain\n\n");
        printf("Hello, you are still learning C!!\n");
        printf("Number of arguments to the main function: %d\n", argc);
        for(i=0; i<argc; i++)
        {
                printf("arguments number %d is %s\n", i, argv[i]);
        }

        printf("QUERY_STRING got by getenv: %s;\n\n", getenv("QUERY_STRING"));
        i=0;
        while(env[i])
        {
                printf("env[%d]=%s\n",i,env[i]);
                i++;
        }
        return 0;
}

Nginx配置(server段)

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.htm index.php index.nginx-debian.html;

        server_name _;

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                fastcgi_pass unix:/run/php/php7.3-fpm.sock;
                #fastcgi_pass 127.0.0.1:9000
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                include fastcgi_params;
        }

        location /cgi-bin {
                gzip off;
                fastcgi_pass unix:/run/fcgiwrap.socket;
                include /etc/nginx/fastcgi.conf; #fastcgi.conf already includes SCRIPT_FILENAME; it's different from fastcgi_param;
                try_files $uri $uri/ /=404;
        }
}

Apache环境运行输出

Hello, you are still learing C!

Number of arguments to the main function:4
argument num 0 is /home/pi/cgidir/hello
argument num 1 is my
argument num 2 is first
argument num 3 is Cproc

Environmental variables:
env[0] = HTTP_HOST=192.168.1.64
env[1] = HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:103.0) Gecko/20100101 Firefox/103.0
env[2] = HTTP_ACCEPT=text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
env[3] = HTTP_ACCEPT_LANGUAGE=en-US,en;q=0.5
env[4] = HTTP_ACCEPT_ENCODING=gzip, deflate
env[5] = HTTP_DNT=1
env[6] = HTTP_CONNECTION=keep-alive
env[7] = HTTP_UPGRADE_INSECURE_REQUESTS=1
env[8] = PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
env[9] = SERVER_SIGNATURE=<address>Apache/2.4.54 (Debian) Server at 192.168.1.64 Port 80</address>

env[10] = SERVER_SOFTWARE=Apache/2.4.54 (Debian)
env[11] = SERVER_NAME=192.168.1.64
env[12] = SERVER_ADDR=192.168.1.64
env[13] = SERVER_PORT=80
env[14] = REMOTE_ADDR=192.168.1.62
env[15] = DOCUMENT_ROOT=/var/www/html
env[16] = REQUEST_SCHEME=http
env[17] = CONTEXT_PREFIX=/cgi-bin/
env[18] = CONTEXT_DOCUMENT_ROOT=/home/pi/cgidir/
env[19] = SERVER_ADMIN=webmaster@localhost
env[20] = SCRIPT_FILENAME=/home/pi/cgidir/hello
env[21] = REMOTE_PORT=4835
env[22] = GATEWAY_INTERFACE=CGI/1.1
env[23] = SERVER_PROTOCOL=HTTP/1.1
env[24] = REQUEST_METHOD=GET
env[25] = QUERY_STRING=my+first+Cproc
env[26] = REQUEST_URI=/cgi-bin/hello?my+first+Cproc
env[27] = SCRIPT_NAME=/cgi-bin/hello

这是因为Apache和fastcgi_wrap对CGI程序的参数传递方式不同:

  1. 原因:

    • Apache的CGI实现会自动将QUERY_STRING按空格分割后传入程序的argv[];
    • 而fastcgi_wrap(配合Nginx使用时)仅会把QUERY_STRING作为环境变量传递,不会解析分割后传入argv[],这是它的默认行为。
  2. 解决方案:

    • 如果你希望和Apache环境下的行为一致,需要自己在代码中解析QUERY_STRING环境变量,分割成参数后处理。示例代码如下:
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      int main(int argc, char *argv[], char *env[])
      {
              int i=0;
              char *query_str = getenv("QUERY_STRING");
              // 自定义参数列表,用于存储解析后的QUERY_STRING参数
              char *custom_argv[100];
              int custom_argc = 0;
      
              printf("Content-type:text/plain\n\n");
              printf("Hello, you are still learning C!!\n");
      
              // 解析QUERY_STRING(URL中空格会编码为+,按+分割)
              if(query_str != NULL) {
                      char *token = strtok(query_str, "+");
                      while(token != NULL) {
                              custom_argv[custom_argc++] = token;
                              token = strtok(NULL, "+");
                      }
              }
      
              // 输出原始argv信息
              printf("Number of arguments to the main function: %d\n", argc);
              for(i=0; i<argc; i++)
              {
                      printf("arguments number %d is %s\n", i, argv[i]);
              }
      
              // 输出解析后的QUERY_STRING参数
              printf("\nParsed QUERY_STRING arguments: %d\n", custom_argc);
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 14:36:19