CGI的一些知識點


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.lyinfo.net.cn/webclass/cgi/default.htm
http://blog.csdn.net/ablo_zhou/article/details/3634954
http://www.ietf.org/rfc/rfc3875


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM