CGI的一些知識點

技術mix呢發表於2018-01-08

CGI(Common Gateway Interface)是能讓web伺服器和CGI指令碼共同處理客戶的請求的協議。它的協議定義文件是http://www.ietf.org/rfc/rfc3875

其中Web伺服器負責管理連線,資料傳輸,網路互動等。至於CGI指令碼就負責管理具體的業務邏輯。

Web伺服器的功能是將客戶端請求(HTTP Request)轉換成CGI指令碼請求,然後執行指令碼,接著將CGI指令碼回復轉換為客戶端的回覆(HTTP Response)。

CGI的指令碼請求有兩部分:請求後設資料(request meta-variables)和相關的訊息體(message-body)。

請求後設資料

包含:

                               "AUTH_TYPE" | "CONTENT_LENGTH" |
                           "CONTENT_TYPE" | "GATEWAY_INTERFACE" |
                           "PATH_INFO" | "PATH_TRANSLATED" |
                           "QUERY_STRING" | "REMOTE_ADDR" |
                           "REMOTE_HOST" | "REMOTE_IDENT" |
                           "REMOTE_USER" | "REQUEST_METHOD" |
                           "SCRIPT_NAME" | "SERVER_NAME" |
                           "SERVER_PORT" | "SERVER_PROTOCOL" |
                           "SERVER_SOFTWARE" | scheme |
                           protocol-var-name | extension-var-name
 
下面一個一個看:
 
AUTH_TYPE是唯一標識了使用者的認證方式,比如basic,Digest等
CONTENT_LENGTH是請求訊息體的長度
CONTENT_TYPE是標識訊息體的格式
GATEWAY_INTERFACE標識使用的CGI的版本,比如CGI/1.1
PATH_INFO說明了解釋CGI指令碼的地址
PATH_TRANSLATED就是可以被訪問的cgi的路徑,它對應CGI指令碼的路徑,比如
http://somehost.com/cgi-bin/somescript/this%2eis%2epath%3binfo
對應的PATH_INFO就是/this.is.the.path;info
QUERY_STRING 請求引數(GET的引數就是放在這個裡面的)
REMOTE_ADDR標識客戶端的ip地址
REMOTE_HOST標識的是客戶端的域名
REMOTE_IDENT是發出請求的使用者標示,大多數服務端選擇忽略這個屬性
REMOTE_USER是使用者的合法名稱
REQUEST_METHOD是請求方法,包括GET/POST/PUT/DELETE等
SCRIPT_NAME是指令碼程式的虛擬路徑,比如是/test/test.php
SERVER_NAME是WEB伺服器的域名
SERVER_PORT是WEB伺服器埠名
SERVER_PROTOCOL是WEB伺服器與客戶端的互動請求協議
SERVER_SOFTWARE傳送給客戶端的response的Web伺服器的標識,比如nginx/1.0.6

請求訊息體

就是直接將客戶端的請求訊息體轉發,將訊息體放在stdin中傳遞給script的
 

相關知識點

引數傳遞

下面的問題就是web伺服器獲取了http請求後,由於http請求是有分GET和POST等方法的。引數怎麼傳遞給可執行程式呢?
比如GET方法,CGI程式就會從環境變數QUERY_STRING中獲取資料。
POST呢?Web伺服器會通過stdin(標準輸入)想CGI中傳送資料的。而傳送的資料長度就是放在CONTENT_LENGTH中的。
對應於HTTP請求,QUERY_STRING存放http的GET引數,stdin存放HTTP的BODY引數

現在流行的nginx+php的方法就是使用nginx(web伺服器)將請求變成cgi請求到php-cgi上,然後php-cgi程式執行php,將返回值變成cgi response返回給nginx。nginx再將它變成http回覆返回給客戶端。

但是這裡有個問題,cgi是單程式的,一個程式的生命期就只是請求進來,處理,返回回覆這幾個階段。但是web伺服器都是需要接受多個web請求的,這裡就需要在後端開啟多個cgi了。一般的cgi伺服器都會設定允許開啟多少個cgi的數量的。

這裡要明確一點,cgi是有分服務端和客戶端的區別的,cgi客戶端是放在web伺服器一側,像nginx,apache這樣的web伺服器就已經是實現了這個客戶端。伺服器端需要另外重啟。像nginx+cgi+php這樣的配合就需要啟動php-cgi服務,當然你也可以想到這樣的服務一定是以deamon的形式在後臺執行,然後會fork出很多個cgi程式。
 

複用

當然有人會問,cgi程式不能複用是個問題,為什麼不呢,fastcgi出現就是解決了這個問題。它的一個程式可以處理多個請求。這樣速度當然就升上去了。然後還有一種cgi是scgi(simple cgi),scgi和fastcgi相似,只能說它定義的協議更簡單(所以才叫做simple)。scgi的客戶端是c寫的,服務端是perl寫的。

就最常見的nginx+cgi+php來說,要明確一點php中$_SERVER中獲取的資訊實際都是從cgi中獲取的,當然這個和nginx中獲取的客戶端資訊是一致的。另外由於cgi是有客戶端和服務端的區別的,因此很容易想到cgi客戶端需要使用tcp與客戶端連線,每個連線當然需要佔用一個埠,因此還是會有埠限制的。所以從這個角度上說,並不是cgi開的越多越好(當然6w的埠限制是遠遠夠的了)。
 

安全

關於開啟的cgi安全問題,曾經鳥哥就爆出了一個bug:http://www.laruence.com/2010/05/20/1495.html
有興趣的讀者可以看看。
 

還有cgi伺服器不是在監聽埠嗎?怎麼防止外網的請求執行cgi呢?我們一般的辦法就是直接繫結在127.0.0.1的ip地址上,保證只有本機才能訪問

本文轉自軒脈刃部落格園部落格,原文連結:http://www.cnblogs.com/yjf512/archive/2012/12/24/2830730.html,如需轉載請自行聯絡原作者


相關文章