在 FastCGI 环境中,GET 参数是作为环境变量的一部分传递给你的应用程序的,你不需要像解析 POST 数据那样去读取标准输入,而是直接从环境变量中读取即可。

(图片来源网络,侵删)
理解 GET 请求的构成
一个典型的 URL 如下:
http://www.example.com/index.php?name=John&age=30&city=New+York
这个 URL 可以分解为:
- 请求路径:
/index.php - 查询字符串:
?name=John&age=30&city=New+York
在 FastCGI 协议中:

(图片来源网络,侵删)
- 请求路径 通常会设置在
SCRIPT_NAME或PATH_INFO等环境变量中。 - 查询字符串 会完整地放在一个名为
QUERY_STRING的环境变量中。
关键的环境变量
要获取 GET 参数,你主要需要关注以下几个环境变量:
QUERY_STRING: 这是最重要的一个,它包含了 URL 中问号 之后的所有内容,未经 URL 解码。- 对于上面的 URL,
QUERY_STRING的值就是"name=John&age=30&city=New+York"。
- 对于上面的 URL,
REQUEST_METHOD: HTTP 请求方法,"GET","POST",你可以用它来判断请求类型。CONTENT_TYPE(或HTTP_CONTENT_TYPE): 如果是 POST 请求,这个变量会告诉你请求体的内容类型(如application/x-www-form-urlencoded)。CONTENT_LENGTH: 如果是 POST 请求,这个变量会告诉你请求体的长度。
如何获取 GET 参数(分语言示例)
获取 GET 参数的通用步骤是:
- 从环境变量
QUERY_STRING中获取原始的查询字符串。 - 将查询字符串按照
&分割成键值对。 - 对每个键值对,按照 分割成键和值。
- (重要) 对键和值进行 URL 解码,因为
QUERY_STRING中的空格是 或%20,特殊字符是 编码的。
1 C/C++ 示例
在 C/C++ 中,你可以使用 getenv() 函数来读取环境变量,解析过程需要手动完成。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// 一个简单的 URL 解码函数
void url_decode(char *dst, const char *src) {
char a, b;
while (*src) {
if (*src == '%' && ((a = src[1]) && (b = src[2])) && (isxdigit(a) && isxdigit(b))) {
if (a >= 'a')
a -= 'a'-'A';
if (a >= 'A')
a -= ('A' - 10);
else
a -= '0';
if (b >= 'a')
b -= 'a'-'A';
if (b >= 'A')
b -= ('A' - 10);
else
b -= '0';
*dst++ = 16 * a + b;
src += 3;
} else if (*src == '+') {
*dst++ = ' ';
src++;
} else {
*dst++ = *src++;
}
}
*dst++ = '\0';
}
int main(void) {
// 1. 从环境变量获取 QUERY_STRING
char *query_string = getenv("QUERY_STRING");
if (query_string == NULL) {
query_string = "";
}
printf("Content-Type: text/html\r\n\r\n");
printf("<html><head><title>FastCGI GET Params</title></head><body>");
printf("<h1>Received GET Parameters</h1>");
// 2. 解析查询字符串
char *key, *value;
char *param = strtok(query_string, "&");
while (param != NULL) {
key = param;
value = strchr(param, '=');
if (value != NULL) {
*value = '\0'; // 分割 key 和 value
value++; // value 指向 '=' 后面的第一个字符
}
// 3. 对 key 和 value 进行 URL 解码
char decoded_key[1024];
char decoded_value[1024];
url_decode(decoded_key, key);
if (value) {
url_decode(decoded_value, value);
} else {
decoded_value[0] = '\0';
}
printf("<p><b>Key:</b> %s, <b>Value:</b> %s</p>", decoded_key, decoded_value);
param = strtok(NULL, "&");
}
printf("</body></html>");
return 0;
}
2 PHP 示例
PHP 是最常用于 FastCGI 的语言之一,在 PHP 中,这一切都由 PHP 引擎自动处理,你只需要使用超全局变量 $_GET 即可。

(图片来源网络,侵删)
<?php
// PHP 会自动解析 QUERY_STRING 并填充到 $_GET 超全局变量中
// 你不需要手动读取 QUERY_STRING 或进行 URL 解码
header('Content-Type: text/html; charset=utf-8');
echo "<html><head><title>FastCGI GET Params (PHP)</title></head><body>";
echo "<h1>Received GET Parameters</h1>";
// 直接遍历 $_GET 数组
if (!empty($_GET)) {
foreach ($_GET as $key => $value) {
// PHP 已经自动对键和值进行了 URL 解码
echo "<p><b>Key:</b> " . htmlspecialchars($key) .
", <b>Value:</b> " . htmlspecialchars($value) . "</p>";
}
} else {
echo "<p>No GET parameters received.</p>";
}
echo "</body></html>";
?>
注意: 使用 htmlspecialchars() 是为了防止 XSS 攻击,这是一个良好的安全实践。
3 Python (Flask) 示例
如果你使用 Python 的 WSGI 框架(如 Flask、Django)来处理 FastCGI,获取参数的方式与普通的 WSGI 应用完全相同。
# app.py
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def get_params():
# request.args 是一个 MultiDict 对象,包含了所有 GET 参数
# 它已经自动处理了 URL 解码
name = request.args.get('name', 'Guest') # 提供默认值 'Guest'
age = request.args.get('age', type=int) # 可以指定类型,自动转换
response_html = f"""
<html>
<head><title>FastCGI GET Params (Python Flask)</title></head>
<body>
<h1>Received GET Parameters</h1>
<p><b>Name:</b> {name}</p>
<p><b>Age:</b> {age}</p>
</body>
</html>
"""
return response_html
if __name__ == '__main__':
# 开发时可以直接运行,生产环境需要配合 cgi 或 flup 等库来运行 FastCGI
# flup.fcgi.FCGI().run(wsgi_app=app)
app.run(debug=True)
GET vs. POST 参数
这是一个非常重要的区别,尤其是在处理 FastCGI 时:
| 特性 | GET 参数 | POST 参数 |
|---|---|---|
| 数据来源 | QUERY_STRING 环境变量 |
标准输入 |
| 数据格式 | key1=value1&key2=value2 |
key1=value1&key2=value2 (通常是 application/x-www-form-urlencoded) |
| 获取方式 | 直接读取环境变量 | 需要从 stdin 读取,并根据 CONTENT_LENGTH 读取指定长度的数据 |
| 大小限制 | 通常受 URL 长度限制(约 2048 字符) | 理论上只受服务器配置限制 |
| 安全性 | 参数会显示在 URL 和服务器日志中,不适合敏感信息 | 数据在请求体中,相对更安全 |
POST 参数获取示例 (C/C++)
// ... (url_decode 函数同上) ...
int main(void) {
printf("Content-Type: text/html\r\n\r\n");
printf("<html><body>");
// 检查是否是 POST 请求
char *request_method = getenv("REQUEST_METHOD");
if (request_method && strcmp(request_method, "POST") == 0) {
// 获取 Content-Length
char *content_length_str = getenv("CONTENT_LENGTH");
int content_length = 0;
if (content_length_str) {
content_length = atoi(content_length_str);
}
if (content_length > 0) {
// 从标准输入读取 POST 数据
char *post_data = (char *)malloc(content_length + 1);
fread(post_data, 1, content_length, stdin);
post_data[content_length] = '\0';
printf("<h1>Received POST Data:</h1>");
printf("<pre>%s</pre>", post_data);
// 解析 POST 数据的逻辑与 GET 类似
// ...
free(post_data);
}
} else {
printf("<p>This script only handles POST requests.</p>");
}
printf("</body></html>");
return 0;
}
- GET 参数在
QUERY_STRING: GET 参数不是通过标准输入传递的,而是通过名为QUERY_STRING的环境变量。 - 自动解析: 像 PHP、Python Flask、Ruby on Rails 等高级语言和框架已经为你封装好了从
QUERY_STRING读取、解析和 URL 解码的繁琐过程,直接使用$_GET、request.args等即可。 - 手动解析: 如果你使用 C/C++ 等底层语言,你需要自己编写代码来读取
QUERY_STRING,按&和 分割,并进行 URL 解码。 - 区分 GET 和 POST: 一定要通过
REQUEST_METHOD环境变量来判断请求类型,并分别从QUERY_STRING(GET) 和stdin(POST) 获取数据。
