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有 2 種風格: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 中的標頭,則必須在腳本開頭呼叫 header 。

IE;

header('內容類型: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:

相關內容