foxpro web 开发原理(四)
今天的文章是我们的最重要的一篇文章,读完这篇文章,我们就完全了解CGI的来龙去脉,你完全可以根据这个原理,运用自己擅长的编程语言,开发出自己的Web开发工具,一个贴合自己的应用程序的web开发应用,随时可以根据自己的需求更改的web开发应用。相信有些已经拥有foxweb,vfpweb等web应用程序的朋友会嗤之以鼻,人家早就有了,拿来用就行了。。。呃,我想说是的,的确早就有现成的,拿来就可以用的。如果你想熟练运用,可能需要全网搜索说明档,范例,源代码等,否则就算拿到软件,也不知道怎么运用,最后可能还是要花钱去买。而你当初想用这些软件的时候就是不想破费。。。
当然,我向来是支持知识付费的,因为很有可能我们也希望能运用自己的知识技能来获得财富。至少我们付费购买这些知识可以节省时间成本,快速地让自己的应用落地,从而赚钱,事实上,很多大神就是这么做的。像我这样的野生程序员,其实是很羡慕的,无法运用自己的知识快速变现,只能苦逼地为了生活奔波,偶尔抽点时间在论坛里发表几篇文章,证明自己还是有点技术的,只是生不逢时,选错了职业而已。。。
言归正传,今天我们要做到的是,如何让我们CGI去执行我们编写的脚本,再把执行后的结果返回给IIS服务器(也可以是其他服务器,原理都一样。)记得,当初有人在论坛里提问,如何在运行时执行grid里某个特定单元格,或行,或列的代码时,很困惑,因为设计时并没有写入代码,而是运行时,希望它能运行我们的某段代码,论坛里的解决方案是,用bindevent函数,这是个强大的函数,可以在运行时刻,让原本没有编写代码的事件运行某段代码。而看完这篇文章,或许你有不一样的解决方案。
依然以control为例,我们在编译它的时候,并不知道它要运行什么样的脚本,而脚本是文本的,也就是说,要实时编译它,并运行。所幸foxpro有这个功能函数,compile!
先来设计我们的脚本sample.fpx,我们探讨的是原理,所以尽量简单,让大伙明白。
只用了一句,代码如下:
response.write("It is success when you see this message!")
如果能正确运行,就显示这句英文“当你看到这条消息时,那就是成功了!”这里的response是我们在control中申明的一个public的对象,只有这样,我们的脚本和我们的CGI程序才有内在的联系,实时上,成熟的web应用都有这样的对象,如request,server,cookie,session等,用以保存服务器一些特定的信息,以及执行某些特定的功能。
昨晚在foxpro web 开发原理(三)中对control做了一点更改,或者说升级,为今天的修改埋下伏笔。感兴趣的可以参考:https://bbs.bc-cn.net/thread-514324-2-1.html
今天我们对CASE cmethod="GET" 的分支做进一步改进,让它开始执行脚本!
改进后的control代码如下:

* CGI处理示例 * 定义 Windows API 常量 #DEFINE STD_INPUT_HANDLE -10 #DEFINE STD_OUTPUT_HANDLE -11 * 声明 Windows API DECLARE Sleep IN kernel32 INTEGER dwMilliseconds DECLARE INTEGER GetStdHandle IN kernel32 INTEGER nStdHandle DECLARE INTEGER ReadFile IN kernel32 ; INTEGER hFile, ; STRING @lpBuffer, ; INTEGER nNumberOfBytesToRead, ; INTEGER @lpNumberOfBytesRead, ; INTEGER lpOverlapped DECLARE INTEGER WriteFile IN kernel32 ; INTEGER hFile, ; STRING lpBuffer, ; INTEGER nNumberOfBytesToWrite, ; INTEGER @lpNumberOfBytesWritten, ; INTEGER lpOverlapped * CGI 环境变量常量 CGI_CONTENT_LENGTH = "CONTENT_LENGTH" cmethod=GETENV("REQUEST_METHOD") * 主程序 CLEAR SET TALK OFF SET CONSOLE OFF * 获取标准输入输出句柄 hStdIn = GetStdHandle(STD_INPUT_HANDLE) hStdOut = GetStdHandle(STD_OUTPUT_HANDLE) * 调试用暂停(如果需要) * [color=#808080]=Sleep(6000) && 暂停60秒等待调试器附加[/color] lcResponse="" PUBLIC response &&创建public对象response,实例化myresponse response=CREATEOBJECT("myresponse", hStdOut) DO CASE CASE cmethod="POST" * 读取POST内容 lcContentLength = GETENV(CGI_CONTENT_LENGTH) lnContentLength = VAL(lcContentLength) IF lnContentLength > 0 * 准备缓冲区 lcReadBuffer = REPLICATE(CHR(0), lnContentLength) lnBytesRead = 0 * 读取输入 =ReadFile(hStdIn, @lcReadBuffer, lnContentLength, @lnBytesRead, 0) lcReadBuffer = LEFT(lcReadBuffer, lnBytesRead) * 解析参数 lnPos = AT("=", lcReadBuffer) IF lnPos > 0 lcValue = SUBSTR(lcReadBuffer, lnPos + 1) ELSE lcValue = lcReadBuffer ENDIF ELSE lcValue = "" ENDIF * 构建响应 lcResponse = "HTTP/1.0 200 OK" + CHR(13) + CHR(10) + ; "Content-Type: text/html" + CHR(13) + CHR(10) + ; CHR(13) + CHR(10) + ; "Hello " + lcValue CASE cmethod="GET" SET PATH TO cpath=GETENV("PATH_TRANSLATED") cquerystr=GETENV("QUERY_STRING") IF FILE(cpath) && 直接检查脚本文件是否存在 * 构建响应头 lcResponse1 = "HTTP/1.0 200 OK" + CHR(13) + CHR(10) + ; "Content-Type: text/html" + CHR(13) + CHR(10) + ; CHR(13) + CHR(10) response.write(lcResponse1) response.write("请求路径为: " + cpath+"<br>"+; "请求参数为:" +IIF(EMPTY(cquerystr),"没有参数!",cquerystr)) response.write("<br>") * 编译后直接执行.fpx文件 COMPILE (STRTRAN(cpath,"fpx","prg")) DO (JUSTFNAME(cpath)) RETURN ELSE lcResponse = "HTTP/1.0 200 OK" + CHR(13) + CHR(10) + ; "Content-Type: text/html" + CHR(13) + CHR(10) + ; CHR(13) + CHR(10) + ; "错误:请求的脚本"+cpath+"不存在或已删除!" ENDIF OTHERWISE lcResponse = "HTTP/1.0 200 OK" + CHR(13) + CHR(10) + ; "Content-Type: text/html" + CHR(13) + CHR(10) + ; CHR(13) + CHR(10) + ; "错误:目前只支持GET和POST方法!" ENDCASE * 发送响应 IF !EMPTY(lcResponse) lnBytesWritten = 0 =WriteFile(hStdOut, lcResponse, LEN(lcResponse), @lnBytesWritten, 0) ENDIF * 清理 CLEAR DLLS RETURN * 构建myresponse类 DEFINE CLASS myresponse as Custom hStdOut = 0 PROCEDURE Init LPARAMETERS hOutput THIS.hStdOut = hOutput ENDPROC PROCEDURE write LPARAMETERS cstring lnBytesWritten = 0 =WriteFile(THIS.hStdOut, cstring, LEN(cstring), @lnBytesWritten, 0) ENDPROC ENDDEFINE
当运行不存在的脚本时,结果如下:
当运行存在的脚本时,结果如下:
到此,我们web开发的原理全部走通,接下来,就是完善它!!!