樹莓派WEB伺服器(Boa)CGI程式設計入門
通過上一個課程“Boa基本設定與使用”的學習,大家在樹莓派上應已經會安裝、配置、執行Boa伺服器,並且訪問到伺服器上的一個靜態網頁。
這不是執行Web伺服器最終的目的,最終應是通過B/S(瀏覽器/伺服器)模式實現兩端的相互。
下面通過一個CGI程式設計例項來學習,WEB伺服器的動態程式設計技術。“體重指數(BMI)計算器”,使用者輸入自己的身高與體重後點擊計算,伺服器就會計算出BMI數值。
體重指數(BMI)計算器
開發設計流程
一、HTML靜態顯示
1 . 靜態的html檔案
cgi.html
<html>
<body>
<div align="center">
<form action="bmi.cgi" method="GET">
<table>
<tr><td rowspan="3"><img src="bmi.png" hight="60" width="120"></td>
<td align="center" colspan ="3"><h2>體重指數(BMI)計算器</h2></td></tr>
<tr><td >身高 : <input type="text" name="cm" size="3"> cm </td>
<td >體重 : <input type="text" name="kg" size="3"> kg </td>
<td align="center" ><input type=submit value=" 計 算 " size="16"> </td ></tr>
<tr><td align="center" colspan="3">BMI =
<input type="text" name="ret" value="" size="3" readonly></tr>
</table>
</form>
</br><img src=bmi_index.png >
</div>
</body>
</html>
二、CGI程式輸出頁面
CGI基本概念
CGI:通用閘道器介面(Common Gateway Interface)是一個Web伺服器主機提供資訊服務的標準介面。通過CGI介面,Web伺服器就能夠獲取客戶端提交的資訊,轉交給伺服器端的CGI程式進行處理,最後返回結果給客戶端。
WEB伺服器和CGI程式之間的通訊
伺服器和CGI程式之間是通過標準輸入輸出來進行資料傳遞的,而這個過程需要環境變數的協作方可實現。
1.伺服器將URL指向一個應用程式
2.伺服器為應用程式執行做準備
3.應用程式執行,讀取標準輸入和有關環境變數
4.應用程式進行標準輸出
伺服器上執行的cgi 通過標準輸入(環境變數)來取得客戶端使用者資料,通過標準輸出向客戶端返回資料顯示。
CGI資料輸出
CGI程式如何將資訊處理結果返回給客戶端?這實際上是CGI格式化輸出。
在CGI程式中的標準輸出stdout是經過重定義了的,它並沒有在伺服器上產生任何的輸出內容,而是被重定向到客戶瀏覽器,這與它是由C,還是Perl或Python實現無關。
所以,我們可以用列印來實現客戶端新的HTML頁面的生成。比如,C的printf是向該程序的標準輸出傳送資料,Perl和Python用print向該程序的標準輸出傳送資料。
課程中CGI程式使用C語言程式設計。
向標準輸出傳送網頁內容時要遵守MIME格式規則:
任意輸出前面必須有一個用於定義MIME型別的輸出內容(Content-type)行,而且隨後還必須跟一個空行。
printf( "Content-type:text/html\n\n" );
2 . cgi顯示介面程式
bmi.c
#include<stdio.h>
int main()
{
printf( "Content-type:text/html\n\n" );
printf("<html><body><div align=\"center\">\n");
printf("<form action=\"bmi.cgi\" method=\"GET\"><table> \n");
printf("<tr><td rowspan=\"3\"><img src=\"../bmi.png\" hight=\"60\" width=\"120\"></td> \n");
printf("<td align=\"center\" colspan=\"3\"><h2>體重指數(BMI)計算器</h2></td></tr> \n");
printf("<tr><td >身高 : <input type=\"text\" name=\"cm\" size=\"3\"> cm </td> \n");
printf("<td >體重 : <input type=\"text\" name=\"kg\" size=\"3\"> kg </td> \n");
printf("<td align=\"center\" ><input type=submit value=\" 計 算 \" size=\"16\"> </td></tr> \n");
printf("<tr><td align=\"center\" colspan=\"3\">BMI = \n");
printf("<input type=\"text\" name=\"ret\" value=\" \" size=\"3\" readonly></tr> \n");
printf("</table></form></br><img src=\"../bmi_index.png\" > \n");
printf("</div></body> </html> \n");
return 0;
}
CGI程式的編譯執行
$gcc bmi.c -o bmi.cgi //gcc編譯器編譯
$cp bmi.cgi /var/www/cgi-bin/ //拷貝到boa伺服器設定的cgi-bin目錄
//在客戶端瀏覽器輸入cgi程式地址如:10.1.1.123/cgi-bin/bmi.cgi 回車後就可看到本文最開始顯示的web頁面。
三、CGI程式資料處理
CGI環境變數
對於CGI程式來說,它繼承了系統的環境變數。CGI環境變數在CGI程式啟動時初始化,在結束時銷燬。
當一個CGI程式不是被HTTP伺服器呼叫時,它的環境變數幾乎是系統環境變數的複製。當這個CGI程式被HTTP伺服器呼叫時,它的環境變數就會多了關於HTTP伺服器、客戶端、CGI傳輸過程等專案。
CGI資料傳輸方式
REQUEST_METHOD:它的值一般包括兩種:POST和GET,但我們寫CGI程式時,最後還要考慮其他的情況。
1.POST方法
如果採用POST方法,那麼客戶端來的使用者資料將存放在CGI程序的標準輸入中,同時將使用者資料的長度賦予環境變數中的CONTENT_LENGTH。
2.GET方法
在該方法下,CGI程式無法直接從伺服器的標準輸入中獲取資料,因為伺服器把它從標準輸入接收到得資料編碼到環境變數QUERY_STRING(或PATH_INFO)。
3.POST與GET的區別
以 GET 方式接收的資料是有長度限制,而用 POST 方式接收的資料是沒有長度限制的。並且,以 GET 方式傳送資料,可以通過 URL 的形式來發送,但 POST方式傳送的資料必須要通過 Form 才到傳送。
CGI程式實現步驟
從伺服器獲取資料
C語言實現程式碼:
POST方法
length = atoi(getenv(“CONTENT_LENGTH”));
inputstring = malloc(sizeof(char)*length + 1);
fread(inputstring, sizeof(char), length, stdin);
GET方法
inputstring = getenv(“QUERY_STRING”);
CGI程式獲取資料都是連續字串要進行解析才能得到獨立資料。
getvalue.h檔案中給出處理函式get_value( )
3 . cgi資料動態處理程式
在上面bmi.c基礎上進行修改,首先在main函式最前面加上以下程式碼。
int main(){
char *val_cm = NULL;
char *val_kg = NULL;
int cm,kg,len=0;
float mm,bmi=0.0;
set_env(getenv("REQUEST_METHOD"),
getenv("CONTENT_LENGTH"),
getenv("QUERY_STRING"));
//<input type="text" name="cm" size="3">
val_cm = get_value("cm"); //通過變數名獲取身高
val_kg = get_value("kg"); //通過變數名獲取體重
cm = atoi(val_cm);
kg = atoi(val_kg);
if(cm > 0 && kg > 0){
mm = cm/100.0;
bmi = (kg / (mm * mm));
}
...
//這裡是頁面顯示程式碼
...
}
下面輸出bmi資料的html程式碼。
printf("<input type=\"text\" name=\"ret\" value=\" \" size=\"3\" readonly></tr> \n");
修改成輸出計算出使用者資料的程式碼。
if(bmi == 0.0)
printf("<input type=\"text\" name=\"ret\" value=\" \" size=\"3\" readonly></tr> \n");
else
printf("<input type=\"text\" name=\"ret\" value=\" %4.2f \" size=\"3\" readonly></tr> \n",bmi);
編譯後copy到cgi-bin目錄,現在使用者在瀏覽器就可以輸入資料提交後,伺服器計算結果顯示。
如果瀏覽器出現502錯誤,說明 cgi程式執行有問題。可以在終端下執行除錯。