CGI 脚本:何时可以返回文档,而不是 HTTP 响应?

CGI 脚本:何时可以返回文档,而不是 HTTP 响应?

下面的脚本 1 是 bash,位于https://example.com/cgi-bin/test。它在获取时生成输出“正在建设中”。它回显StatusContent-type标题以及一些 HTML。如果我尝试回显整个 HTML 文档,Apache 只会抱怨标题无效。

下面的脚本 2 是 php,位于https://example.com/cgi-bin/test2.php。与 bash 脚本不同,此脚本返回 HTML 文档。

为什么脚本 2 可以发送整个 HTML 文档,而脚本 1 却不能?

脚本 1

#!/bin/bash
cat <<'EOF'
Status: 200 OK
Content-type: text/html

<p>Under construction.</p>
EOF

脚本 2

<?php
print <<<EOF  
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    ...etc
  </head>

  <body>
  ...etc
  </body>
</html>
EOF;
?>

编辑

php有两种版本:CLI 和 CGI​​ 版本。如果您只是从命令行运行脚本 2,php test2.php那么仅有的产生的输出php正是您所看到的:HTML 文档php-cgi是 CGI 版本(在 Ubuntu/Deb 上安装为apt install php-cgi)。Apache(有效地)运行 CGI 版本(在现实生活中,它执行此操作略有不同,但结果相同):

 $ php-cgi test2.php
Content-type: text/html; charset=UTF-8

<!DOCTYPE html>
...rest of doc

CGI 脚本至少必须返回Content-typeApache(但可以返回更多标头,包括Status)。所以答案是两个都脚本能够工作是因为脚本 1 明确返回了Content-type,而的底层 CGI 版本也php做了同样的事。

bash 脚本可以返回整个 HTML 文档,只要它还返回Content-type.

答案1

在 CGI 中,您需要发送 Content-Type。PHP 会为您生成它。(通过浏览器检查输出,即使您在代码中看不到它,您也会看到它。)

我有一个用 C 语言编写的 CGI,你确实需要内容类型;

就我的情况而言;

printf("内容类型:text/html;charset=us-ascii\n\n");

如果您需要更改 php 中的标题,则必须在脚本开始时调用标题。

IE;

标头('内容类型:application/json');

答案2

在这种情况下,PHP 和 CGI​​ 是两种不同的东西。

CGI 是程序(在本例中为 bash 脚本)与 Web 服务器之间的接口。此接口指定 Web 服务器与程序之间的通信。

该标准要求程序返回全部标头(包括状态标头)位于实际内容之前。在 HTTP 中,标头和正文由一行分隔 - 因此格式如下

Header
Header

Content

在标题之后,您可以自由地包含完整的 HTML 文档 - 或者与您发送的标题匹配的任何其他类型的数据。

PHP 为您做出了一些假设,除非您覆盖它,否则它会自动设置内容类型、状态代码等。

答案3

如果通过 Apache 通过 CGI 调用脚本,则需要包含有效的 CGI 标头响应,而不是 HTTP 响应。我认为从本质上讲(详见下文),您需要从文件中删除“状态:200 OK”,这样它可能会起作用。

Apache 自己写了一篇很好的文章(https://httpd.apache.org/docs/2.2/howto/cgi.html) 显示获得有效响应所需的最低限度。

客户端收到的示例标头可能如下:

HTTP/1.x 200 OK
Transfer-Encoding: chunked
Date: Tue, 06 Dec 2021 19:58:00 GMT
Server: My_Bash_Script
Connection: close
X-Powered-By: My_Bash_Script
Pragma: public
Expires: Tue, 06 Dec 2021 20:58:00 GMT
Cache-Control: max-age=3600, public
Last-Modified: Tue, 06 Dec 2021 20:58:00 GMT
Content-Encoding: gzip
Vary: Accept-Encoding, Cookie, User-Agent
Content-Type: text/html; charset=UTF-8
 
<!DOCTYPE html>
<head><title>Under construction</title>
<body><p>Under construction.</p></body>
</html>

但是你的CGI,只需要从“Content-Type:text/html;charset=UTF-8”向下发送。

这里有一篇相当不错的文章来解释标题: https://code.tutsplus.com/tutorials/http-headers-for-dummies--net-8039

对于通过 Apache 提供的 PHP 文件,存在几层通信:

  • Apache 在 TCP 端口上发出请求。如果通过 HTTP,则包括请求标头。
  • Apache 运行任何规则(例如 mod_rewrite)并处理所需的任何 SSL 连接/握手。
  • 然后 Apache 检测文件扩展名是 PHP,并通过 PHP 解释器调用 PHP 脚本。
  • PHP 代码被解释并转换成静态字符串(希望如此 :-),该字符串返回给 Apache 并包含 HTML 代码。
  • 然后,Apache 将标头信息连同任何其他出站处理一起添加到 HTML 页面。
  • 它被序列化并通过 TCP 连接传回客户端。

探索标头的另一种好方法是使用 Firefox/Chrome 开发人员工具(在 Firefox 中按 F12 即可打开它们)。打开开发人员工具后,转到“网络”选项卡并重新加载页面(Windows/Linux 上按 Ctrl + R)。有一个“原始”选项,您可以在其中查看发送和接收的确切数据。

最后,如果您发现某个网站,或者您的 CGI 是通过 http 而不是 https 提供的,您可以安装 Wireshark (https://www.wireshark.org) 并轻松监控流量对话以了解您发送的被误解的内容与 Apache 提供的正常静态 html 页面对话之间的差异。

PS(2022 年),如果您确实在运行 Apache 2.2:

相关内容