MasteringVFP/17/1

出自VFP Wiki

在2006年10月18日 (三) 14:46由Elleryq (對話 | 貢獻)所做的修訂版本
跳轉到: 導航, 搜尋

目錄

VFP與CGI

簡介

在網址上有時候會看到類似 http://www.your_site.com/xxx.exe?xxx=yyy 的網址,那並不是一個常見的 .exe, 而是實做了 CGI 介面的 .exe.

甚麼是 CGI ?? CGI 的全名是 Common Gateway Interface,也就是一種介面。只要你的應用程式實做此一介面,Web server 就可以據此與你的應用程式溝通。

原理

CGI是怎麼與Web Server溝通的呢?HTML 裡面有所謂的 Form,你可以指定 Form 的 method 為 POST 或 GET。POST 與 GET 決定了 CGI 該怎麼去取得資料;如果是 POST,那麼 Web server 會把這些資料放到 STDIN (標準輸入資料流)去,你的 CGI 就應該使用標準輸入函數去讀取這些資料;如果是 GET,Web server 會把這些資料放到名為 QUERYSTRING 的環境變數裡,於是你需要使用取環境變數的函數來取得這些資料。至於輸出的部份,統一都是輸入到 STDOUT (標準輸出資料流)。

之後的所有技術都與 CGI 脫不了關係,都是以 CGI 為基礎發展出來的。所以會了 CGI 之後,後面也會了一半。

事實上,VFP在配合Win32 API 之後,是可以實做出CGI介面的,關鍵的API在於 ReadFile / GetENV / WriteFile 這幾個API。ReadFile 可以讀取 STDIN (標準輸入資料流),GetENV 則可以取得環境變數,於是你已經可以取得 POST 或 GET 的資料。WriteFile 可以輸出到 STDOUT (標準輸出資料流)。

在網路上可以搜索到不少資料:

第二個連結裡面有 VFP 的 sample.

實做CGI以後,你需要考量的是當 Request 過多時的問題。當 request 過多的時候,CGI 的效能並不好。因為 web server 在遇到 request CGI 的時候,會為這個 CGI create 一個 process 起來。當同時遇到 1000, 10000, 100000 ....個 request 的時候,web server 就會去 create 1000、10000、100000 ....個 process, 這會拖垮整個 server 的效能!!

這也是後來為甚麼 script 會大為盛行的原因,因為他們所需要的資源較少,處理以及除錯上也較為方便,不過基礎原理還是一樣的。

簡易範例

*
* Main.prg
*

SET PROCEDURE TO cgilib

LOCAL oResponse
oResponse = CREATEOBJECT( "RESPONSE" )
oResponse.Headers.Add( "text/plain", "Content-type" )
oResponse.Headers.Add( "us-ascii", "charset" )
oResponse.Write( "<p>Hello world!</p>")
*
* cgilib.prg
*
DEFINE CLASS RESPONSE as Custom 
	bDirty = .F.
	bHeaderOut = .F.
	ADD OBJECT Headers AS collection
	
	PROCEDURE Init
		CREATE CURSOR outputCache ( outLine varchar(254) )
	ENDPROC
	
	PROCEDURE destroy
		IF this.bDirty == .T.
			this.flush()
		ENDIF 
		USE IN outputCache 
	ENDPROC
	
	PROCEDURE Write
		LPARAMETERS theHtml
		LOCAL lcOutput
		
		INSERT INTO outputCache values( theHtml )
		this.bDirty = .t.
		RETURN 
	ENDPROC
	
	HIDDEN PROCEDURE InternalWrite
		LPARAMETER lcOutput

		DECLARE INTEGER GetStdHandle in Win32API integer nHandleType
		declare integer WriteFile    in Win32API integer hFile, string @ cBuffer,;
				integer nBytes, integer @ nBytes2, integer @ nBytes3

		LOCAL lnOutHandle
		LOCAL lnBytesWritten
		LOCAL lnOverLappedIO 
		
		lnOutHandle=GetStdHandle(-11) 
		lnBytesWritten=0
		lnOverLappedIO=0
		WriteFile(lnOutHandle, @lcOutput, len(lcOutput), @lnBytesWritten, @lnOverLappedIO)
	ENDPROC
	
	PROCEDURE flushHeader
		LOCAL lcDefaultOutput
		LOCAL lcOutput
		LOCAL lcKey
		local i
		
		lcDefaultOutput="HTTP/1.0 200 OK"+chr(13)+chr(10)
		lcOutput = ""

		FOR i = 1 TO this.Headers.Count
			lcKey = this.Headers.GetKey( i )
			IF !EMPTY( lcKey  ) THEN 
				lcOutput = lcOutput + lcKey + ": " + this.Headers.Item(i) + CHR(13) + CHR(10) 
			ENDIF 
		NEXT 
		
		IF this.Headers.getKey( "Content-type" ) == 0 THEN 
			lcOutput = lcOutput + "Content-type: text/html"+chr(13)+chr(10)
		ENDIF

		lcOutput = lcOutput + chr(13)+chr(10)
		this.InternalWrite( lcDefaultOutput + lcOutput )
		this.bHeaderOut = .T.
	ENDPROC
	
	PROCEDURE flush
		IF this.bDirty == .f. then
			RETURN
		ENDIF 

		LOCAL lcAlias
		LOCAL lcOutput
		
		IF this.bHeaderOut == .F. THEN
			this.flushHeader()
		ENDIF 
		
		lcAlias = ALIAS() 
		SELECT outputCache
		GO top
		SCAN
			lcOutput = outputCache.outLine
			? lcOutput
			this.InternalWrite( lcOutput )
		ENDSCAN
		SELECT( lcAlias )
	ENDPROC
ENDDEFINE

參考資料

系列文章

Day 1

CGI,亦即 Common Gateway Interface,應該說是所有 web server side 技術的前身。

基本的原理是利用標準輸出入與環境變數來作為 web server 與應用程式溝通的介面。

VFP 本身並不支援標準輸出入,必須透過 Windows API 才可以。 所以我們利用 GetStdHandle 取得標準輸出檔案的 Handle,再使用 WriteFile 輸出。

讓我們來看看第一個 CGI 應用程式:

*
* cgi01
*
DECLARE INTEGER GetStdHandle in Win32API integer nHandleType
declare integer WriteFile    in Win32API integer hFile, string @ cBuffer,;
		integer nBytes, integer @ nBytes2, integer @ nBytes3

LOCAL lnOutHandle
LOCAL lnBytesWritten
LOCAL lnOverLappedIO 
LOCAL lcOutput

lnOutHandle=GetStdHandle(-11) 
lnBytesWritten=0
lnOverLappedIO=0
lcOutput = "HTTP/1.0 200 OK"+chr(13)+chr(10) + ;
	"Content-type: text/html"+chr(13)+chr(10) + ;
	CHR(13) + CHR(10) + ;
	"<p>Hello world</p>"

WriteFile(lnOutHandle, @lcOutput, len(lcOutput), @lnBytesWritten, @lnOverLappedIO)

步驟:

  1. 請先建立一個新專案,命名為 vfpcgi,再新增一個 cgi01.prg,把上面的程式碼貼進去,再編譯成 Windows executable (.exe) 檔案,所以你得到了 vfpcgi.exe
  2. 在 c:\inetpub\wwwroot 下新增一個目錄,命名為 vfpcgi,將 vfpcgi.exe 複製到這裡
  3. [控制台][系統管理工具]執行Internet Information Services
  4. 在左邊你會看到 vfpcgi,滑鼠右鍵,選取內容
  5. 點選 "建立" 按鈕,左邊原本黯淡的 TextBox 會亮起來,將使用權限改為"指令及執行檔",應用程式保護選擇為"高",按下確定。
  6. 確定你的 IIS 已經啟動,然後打開你的瀏覽器,在網址列輸入 http://localhost/vfpcgi/vfpcgi.exe,這個時候你應該會看到顯示著 Hello world 的頁面~