java开发cgi_編寫CGI小結(Java)

轉載請注明出處:http://blog.csdn.net/hungryhuang/article/details/6601684。

由於Carl要用到我的程序,我們便合作工作。但是他寫的程序是Python的,我寫的程序是Java的,必須得找一種方式進行通信。盡管有Jython這些東西,但是Carl認為還是CGI最簡便。於是,前陣子開始學學CGI怎么弄。剛開始,覺得好像也不是很難,但是后來進展沒有預期的順利。最后,由於學院的服務器有CGI模塊但是不允許隨便跑CGI,實驗室服務器又裝的是FastCGI,感覺麻煩,最后Carl說還是用socket吧... - - |||。

整體來說,用CGI進行通信這個計划算是破產了。雖然是很老舊、基本都不會再用的東西了,但是由於對我來說是新東西,還是很好奇,沒有實現,自然是一種惋惜。雖然最后沒能用上CGI,但是個人覺得如果學院服務器讓用戶自己跑CGI的話,應該還是沒問題的。無論怎樣,還是記錄下一些基本知識,免得以后又忘了。

CGI年代久遠,不過卻實現了動態網頁。CGI,准確說,應該是種協議(或者說接口),它使得server中的程序(cgi script)能夠通過標准I/O流(STDIN和STDOUT,比如在Java語言里就是System.in和System.out,在C里面就是printf等,只要是能夠進行標准I/O流讀寫的程序,都可以用來實現CGI)讀取到所需的信息和輸出信息給瀏覽器,而這些所要從客戶端讀取的信息則是包含在某些已經被定義好的環境變量中,我們只需要讀取這些環境變量,自然就能獲取想要的值了(這也就是CGI這個借口為我們所做的事)。而通常所說的CGI,也有可能泛指CGI程序,即CGI script,是開發者自己所寫的、處理用戶請求的程序。

總體來說,過程是這樣的:

1. 服務器接受到請求

2. 服務器發現這個請求是需要一個CGI程序來進行處理

3. 服務器建立一個環境,這個運行環境里有一些變量,也就是所謂的CGI程序所需要的環境變量

4. 服務器在這個環境下啟動相應的CGI程序

5. CGI程序解析自己想要的環境變量來獲取所提交的請求信息

6. CGI程序對這些請求信息做相應的處理

7. CGI程序將相應的結果輸出到標准輸出STDOUT,此結果將被輸出到用戶端,呈現給用戶結果。

8. CGI程序執行完畢,退出程序。

比較詳細來說,原理大概是這樣的:

1. 客戶端在瀏覽某個網頁的時候,提交表單(form)。而表單的action則指定了要處理該表單的CGI程序,比如:

上面的程序中,action="/cgi-bin/plus.cgi" 的意思就是說“這個表單里的數據,都交給plus.cgi這個程序處理了,然后它處理完這些數據后,再把結果返回給瀏覽器”。

需要說明的是,plus是一個可執行文件的文件名,比如可能是一個shell文件(例如 plus.sh),其后綴不一定是.cgi。那么為什么要取在這里取名.cgi呢?原因是這樣能說明,這個表單處理,是通過一個類型為cgi的程序進行處理,或者說,通過cgi這種方式讓這個可執行文件對提交的數據進行處理。一般來說,出於安全考慮,不是任何用戶都有權限去寫一個自己的cgi程序然后上傳到服務器、讓該服務器去運行的(比如我們學院的服務器就不行,哎...)。而只有放在服務器指定目錄(一般為cgi-bin)下的可執行文件,才會被被視為是cgi程序,才能被執行。而一般人是無法訪問這個目錄的。

2. 然后,name為“m”和“n”的這兩個變量以及他們的值,就通過某個環境變量輸入到CGI程序中,由CGI程序去進行該CGI程序所指定的處理了。GET和POST獲取“m”和“n”的方式有所不同。如果提交方法是GET的話,那么GET所提交的內容則被包含在名為QUERY_STRING的環境變量中,當得到這個環境變量的值后,將其內容解析出來就可以得到name/value這樣的值對了,就可以進行相應的處理了。而POST的話,則需要從標准輸入流STDIN里面讀取數據,而這些數據到底有多少呢?這個則需要通過讀取CONTENT_LENGTH這個環境變量的值來知道。

像在C語言里面,可以通過getenv函數來直接獲取環境變量的值,比如:getenv("QUERY_STRING"),  getenv("CONTENT_LENGTH")等等。Perl可能要算是寫CGI的最佳語言,但是不會Perl,此處略過。另外,由於我的程序是用Java寫的,就使得讀取環境變量的方式有點特殊,因為Java是沒有直接獲取這些環境變量的函數的。Java為何不能直接訪問環境變量?簡單說,因為Java內部還有一個屬於System這個類的屬性。因此,我們一個System.getProperty獲取的是Java中這個System類的屬性的,而不是環境變量的。這些System的屬性也是以name/value這樣的形式來存儲一些Java運行環境的信息的。因而,額外的環境變量(或者說屬性信息)需要用指令java -D的形式,詳見后面的wrapper程序。

常用的環境變量有:REQUEST_METHOD,QUERY_STRING,CONTENT_LENGTH,PATH_INFO。其他的有:SERVER_SOFTWARE,SERVER_NAME,GATEWAY_INTERFACE,SERVER_PROTOCOL,SERVER_PORT,PATH_TRANSLATED,SCRIPT_NAME,REMOTE_HOST,REMOTE_ADDR,AUTH_TYPE,REMOTE_USER,REMOTE_IDENT,CONTENT_TYPE。如果現在忘記這些是干嘛的了...額...google下吧...

現在,我們已經讀取到了所想要的環境變量。但是,這些環境變量的值,是需要我們進行解析的,因為當初在傳給我們的時候,就是進行了URL編碼的(URL encode)。比如,如果我們提交的表單是GET類型的話,再提交完信息后,可以在地址欄看來類似這樣的url地址:http://www.xxxxxxx.edu/cgi-bin/plus.cgi?m=5&n=6。其中,“m=5&n=6”就是被編碼的字符串,也就是我們想要獲取的值。而“http://www.xxxxxxx.edu/cgi-bin/plus.cgi”是處理該表單的cgi程序的地址。“?”說明后面的字符串(即“m=5&n=6”)是傳入的參數。不難看出,在編碼的時候,類似於這樣的規則“name1=value1&name2=value2&name3=value3”。此外,非西文的字符串將被“%XX”所代替,空格將被“+”代替。具體地,去參考URL encode的相關資料。

如何解析這些麻煩的字符串,不需要自己再動手去寫,網上有很多這樣的函數庫,各種語言。直接用網上現成的函數庫來解析就行了。就Java來說,推薦cgi_lib.java這個庫。很方便,應用也很廣泛,文件也很小。其中函數的功能是跟cgi_lib.pl一樣的。

3. 解析字符串后,我們可以知道變量m的值為5,變量n的值為6。然后就可以在CGI程序中進行相應的處理了。自己想怎么處理就怎么處理。比如,此處是想處理加法,則在自己的CGI程序里實現m和n的加法即可。

4. 處理完了數據,需要將結果呈現給瀏覽器端的用戶。這個簡單,直接用STDOUT就行了。比如,C語言用printf,Java語言用System.out.println之類的。但是需要注意的是,首先輸出的必須是"Content-type: text/plain"(也就是MIME頭信息,告訴server它隨后的輸出是以純ASCII文本的形式),然后下面空一行(必須空一行),再直接打印出要呈現給用戶的html語句。比如,在Java里面,就是:

System.out.println("Content-type: text/plain");

System.out.println("");

比如,要測驗自己是否有權限可以寫一個CGI放在服務器上運行,則可以寫一個最簡單的CGI程序,該程序暫時不處理任何來自用戶的請求,只是輸出"Hello, world"。

shell程序可以寫成:

#!/bin/sh

echo "Content-type: text/html"

echo ""

echo ""

echo "

"

echo "

Hello, world

"

echo ""

echo ""

C語言可以寫成:

#include

void main(void){

printf("Content-type: text/html\n");

printf("\n");

printf("\n");

printf("

\n");

printf("

Hello, world

\n");

printf("");

printf("/");

}

這樣,在客戶端運行就會呈現出

大小的“Hello, world”了。

Java的特別注意:

1.Java讀取環境變量,只能通過-D的option來加以讀取。

2.Java生成的.class文件(比如java_plus.class),這不是一個通常意義上的可執行文件,這個文件只是說通過JVM可以執行起來。而CGI程序是一個直接可以執行的文件。因此,我們需要寫一個wrapper,將這個.class文件封裝起來。當調用這個wrapper程序的時候,這個wrapper程序能通過Java指令運行該.class文件。

結合上訴兩點,則我們可以寫一個shell文件當做wrapper程序,如下:

#!/bin/sh

java \

-Dcgi.content_type=$CONTENT_TYPE \

-Dcgi.content_length=$CONTENT_LENGTH \

-Dcgi.request_method=$REQUEST_METHOD \

-Dcgi.query_string=$QUERY_STRING \

-Dcgi.server_name=$SERVER_NAME \

-Dcgi.server_port=$SERVER_PORT \

-Dcgi.script_name=$SCRIPT_NAME \

-Dcgi.path_info=$PATH_INFO \

java_plus

然后將上面的文件保存為plus.sh,並且放在指定的目錄(比如cgi-bin)即可。這樣,當表單提交新的時候,就會到這個目錄中(因為后綴名為cgi)去尋找名為plus的文件,然后執行這個文件。而在java_plus這個文件中,我們用System.getProperty("cgi.query_string")就可以訪問到QUERY_STRING這個環境變量了。

推薦一些鏈接:

http://www.jmarshall.com/easy/cgi/

http://www.eli.sdsu.edu/courses/spring96/cs596/notes/andrew/cgi.html

http://www.javaworld.com/javaworld/jw-01-1997/jw-01-cgiscripts.html

http://apps.hi.baidu.com/share/detail/18814484

http://www.jaguarpc.com/forums/showthread.php?t=2553

http://httpd.apache.org/docs/current/howto/cgi.html

至於FastCGI,這個效率比傳統CGI高很多。但是,比較麻煩,需要用循環,還要設置端口什么的,就沒動手搞那個,只是看了下相關資料。還是放在這里吧。

http://www.phpchina.com/download/handbook/linux-html/1272.html

http://www.20cn.net/ns/wz/net/data/20030615005558.htm

http://www.fastcgi.com/devkit/doc/fcgi-java.htm

http://www.citycat.ru/doc/FastCGI/fcdk/index.html

http://hi.baidu.com/coffeefoam/blog/item/1446493be749f3e814cecbb8.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值