我为FastCGI遇到accidental usage Status
标头。在与环境无关的脚本中使用它有利有弊吗?
header('Location: ' . $url, true, 301);
单独在Apache 2.2上没有问题(根据phpinfo()
,服务器使用FastCGI)。
该脚本针对的是Apache和nginx(mod_php和FastCGI)。防故障解决方案会是什么样的?
答案 0 :(得分:4)
HTTP状态代码作为HTTP响应第一行的一部分发出。根据{{3}},Status标头是服务器识别的特殊标头,它控制该行并且不会发送到客户端。但是,如果它与非FastCGI服务器适配器一起使用,则服务器将忽略该值,并且可以发送标头。
您已拥有的解决方案是与环境无关的最佳方式。在重定向之后,唯一的补充就是exit
语句,以确保脚本终止。
让我们更仔细地看看幕后发生了什么。
以下PHP重定向代码
header('Location: ' . $url, true, 301);
exit;
将调用ext/standard/head.c
PHP_FUNCTION(header)
{
[ code that just parses the arguments omitted ]
sapi_header_op(rep ? SAPI_HEADER_REPLACE:SAPI_HEADER_ADD, &ctr);
}
这将依次调用sapi_header_op
main/SAPI.c
功能
[ ... ]
switch (op) {
[ ... ]
case SAPI_HEADER_ADD:
case SAPI_HEADER_REPLACE:
case SAPI_HEADER_DELETE: {
sapi_header_line *p = arg;
if (!p->line || !p->line_len) {
return FAILURE;
}
header_line = p->line;
header_line_len = p->line_len;
http_response_code = p->response_code;
break;
}
[ code that splits header line by colon, trims whitespace etc ]
[ special headers handling code, including setting 302 if Location ]
if (http_response_code) {
sapi_update_response_code(http_response_code);
}
sapi_header_add_op(op, &sapi_header);
return SUCCESS;
如果正在使用FastCGI后端,则sapi_cgi_send_headers
sapi/cgi/cgi_main.c
函数最终会发送添加的标头
[ ... ]
if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
{
[ emit status line if cgi.rfc2616-headers is set ]
[ Handle a case where there is a user supplied status line ]
[ Handle a case where there is already a user supplied status header ]
[ if none of the above ]
if (err->str) {
len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->str);
} else {
len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
}
[ ... ]
}
[ ... ]
请注意php_apache_sapi_send_headers
中的sapi/apache2handler/sapi_apache2.c
函数对Status
标头没有任何特殊处理,因为它不用于模块通信。
通过执行上面的PHP代码
所有操作都在SAPI层中执行,SAPI层是HTTP服务器适配器(FastCGI,Apache模块等)之上的抽象层。这是跨环境和可靠的。
从历史上看,FastCGI中存在一些错误,这些错误阻止了301响应正常工作,但这些错误都在Web服务器实现中,而且PHP代码无法解决这个问题。
另见: