![]() |
#2
schtg2025-05-24 16:10
回复 楼主 sam_jiang
|
呃,我想说是的,的确早就有现成的,拿来就可以用的。如果你想熟练运用,可能需要全网搜索说明档,范例,源代码等,否则就算拿到软件,也不知道怎么运用,最后可能还是要花钱去买。而你当初想用这些软件的时候就是不想破费。。。
当然,我向来是支持知识付费的,因为很有可能我们也希望能运用自己的知识技能来获得财富。至少我们付费购买这些知识可以节省时间成本,快速地让自己的应用落地,从而赚钱,事实上,很多大神就是这么做的。像我这样的野生程序员,其实是很羡慕的,无法运用自己的知识快速变现,只能苦逼地为了生活奔波,偶尔抽点时间在论坛里发表几篇文章,证明自己还是有点技术的,只是生不逢时,选错了职业而已。。。
言归正传,今天我们要做到的是,如何让我们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开发的原理全部走通,接下来,就是完善它!!!