题记:用“易语言.飞扬”(EF)开发WEB应用程序,此前还没有先例。但因为EF本地开发包(EFNDK)已经发布,用C/C++开发一个EF类库,使其支持EF开发WEB应用程序,应该并非难事。当然也可想而知,其中必有诸多难点有待解决。此系列文章,为本人探索过程之记录,对外人未必有多大价值。如有网友乐观其事,还请理性待之。作者:liigo。转载请务必注明出处:http://blog.csdn.net/liigo/。在线留言。
试用EF开发WEB应用程序(8):CGI环境变量
FastCGI 是对 CGI 技术的扩展和改进,要写好 FastCGI / CGI 程序,了解、熟悉、深入掌握“CGI环境变量”是必需的。本文将重点介绍CGI规范中规定的标准环境变量,以及FastCGI扩展的环境变量。
在 CGI / FastCGI 规范中,WEB服务器和CGI/FastCGI程序之间交流信息的主要途径是环境变量(以及标准输入输出流)。这里说到的环境变量,是指操作系统中的环境变量。(Windows系统下,PATH 是很常见的一个环境变量;熟悉JAVA的朋友通常都知道一个叫 CLASSPATH 的环境变量;学“易语言.飞扬”(EF) 的哥们也肯定听说过 EF_LIB_PATHS 这个环境变量;……) CGI规范对CGI程序中使用的环境变量名称及其含义做了具体而明确的规定,通常把这些环境变量称为“CGI环境变量”。
下表:CGI环境变量及其介绍
CGI 环境变量名称 |
说明 |
REQUEST_METHOD |
请求类型,如 "GET" 或 "POST" |
CONTENT_TYPE |
被发送数据的类型 |
CONTENT_LENGTH |
客户端向标准输入设备发送的数据长度,单位为字节 |
QUERY_STRING |
查询参数,如 "id=10010&sn=liigo" |
SCRIPT_NAME |
CGI脚本程序名称,如 "/xyz.efcgi" |
PATH_INFO |
CGI脚本程序的附加路径 |
PATH_TRANSLATED |
PATH_INFO对应的绝对路径 |
REMOTE_ADDR |
发送此次请求的主机IP |
REMOTE_HOST |
发送此次请求的主机名 |
REMOTE_USER |
已被验证合法的用户名 |
REMOTE_IDENT |
WEB服务器的登录用户名 |
AUTH_TYPE |
验证类型 |
GATEWAY_INTERFACE |
服务器遵守的CGI版本,如 "CGI/1.1" |
SERVER_NAME |
服务器主机名、域名或IP |
SERVER_PORT |
服务器端口号 |
SERVER_PROTOCOL |
服务器协议,如 "HTTP/1.1" |
SERVER_SOFTWARE |
服务器软件的描述文本 |
DOCUMENT_ROOT |
文档根目录 |
HTTP_ACCEPT |
客户端可以接收的MIME类型,以逗号(,)分隔 |
HTTP_USER_AGENT |
发送此次请求的WEB浏览器 |
HTTP_REFERER |
调用此脚本程序的文档 |
HTTP_COOKIE |
获取COOKIE键值对,多项之间以分号(;)分隔,如 "key1=value1; key2=value2" |
下表:FastCGI 扩展的环境变量
FastCGI 环境变量名称 |
说明 |
FCGI_ROLE |
当前 FastCGI 程序担任的角色,如 "RESPONDER", "AUTHORIZER", "FILTER" |
FCGI_DATA_LENGTH |
服务器发送的数据长度。仅当 FCGI_ROLE 值为 "FILTER" 时有效。 |
FILE_LAST_MOD |
输入文件(input file)的最后修改时间,其值为自1970年1月1日零时零分零秒(世界标准时间,UTC)至今的秒数。仅当 FCGI_ROLE 值为 "FILTER" 时有效。 |
对于以上所有 CGI 环境变量,和 FastCGI 扩展的环境变量,EF类库 fastcgi.efn 中的 FCGI 类均提供同名属性方法,用于读取该环境变量的值。一般来说,这些方法返回文本数据;只有几个例外,是返回整数数据:CONTENT_LENGTH(), FCGI_DATA_LENGTH(), FILE_LAST_MOD()。
此外,WEB服务器通常也会扩展一些环境变量,这种情况下,可用EF类库 fastcgi.efn 中提供的FCGI.getenv() 方法读取任意指定名称的环境变量的值。
下面,我们用EF写一个WEB程序,列出以上所有CGI环境变量及其内容,亲身感受一下CGI环境变量的真实面目,以便加深对它们的理解:
引入fastcgi;
公开类启动类
{
常量文本s
=
[
"
Content-type:text/html
<
html
><
head
>
<
metahttp
-
equiv
=
"
content-type
"
content
=
"
text/html;charset=utf-8
"
>
<
title
>
$(title)
</
title
>
</
head
>
<
body
>
<
h1
>
$(title)
</
h1
>
<
hr
></
hr
>
<
h3
>
PARAMS:
</
h3
>
<
p
>
$(params)
</
p
>
<
hr
></
hr
>
<
h3
>
CGIENVVARS:
</
h3
>
<
p
>
$(cgivars)
</
p
>
<
hr
></
hr
>
<
p
>
byliigo,index:$(index)
</
p
>
</
body
>
</
html
>
"
];
公开静态启动()
{
int
count
=
0
;
FCGIfcgi
=
new
FCGI;
while
(fcgi.Accept()
>=
0
)
{
文本t
=
s.替换全部(
"
$(title)
"
,
"
CGIVARS(byliigo)
"
);
t
=
t.替换(
"
$(params)
"
,get_params(fcgi));
t
=
t.替换(
"
$(cgivars)
"
,get_cgivars(fcgi));
t
=
t.替换(
"
$(index)
"
,count.到文本());
fcgi.Output(t.到UTF8());
count
++
;
}
}
static
stringget_params(FCGIfcgi)
{
strings;
foreach (fcgi.QUERY_STRING_NAMES(),文本name)
{
s
+=
"
<p>
"
+
name
+
"
:
"
+
fcgi.QUERY_STRING(name)
+
"
</p>
"
;
}
return
s;
}
static
stringget_cgivars(FCGIfcgi)
{
strings;
s
+=
"
<p>REQUEST_METHOD:
"
+
fcgi.REQUEST_METHOD
+
"
</p>
"
;
s
+=
"
<p>CONTENT_TYPE:
"
+
fcgi.CONTENT_TYPE
+
"
</p>
"
;
s
+=
"
<p>CONTENT_LENGTH:
"
+
fcgi.CONTENT_LENGTH.到文本()
+
"
</p>
"
;
if
(fcgi.CONTENT_LENGTH
>
0
)
{
binarycontent
=
fcgi.ReadData(fcgi.CONTENT_LENGTH);
s
+=
"
<p>CONTENT:
"
+
content.到文本()
+
"
</p>
"
;
s
+=
"
<p>CONTENT(text):</p><p>
"
+
content.UTF8到文本().替换全部(
"
"
,
"
<br/>
"
)
+
"
</p>
"
;
}
s
+=
"
<p>QUERY_STRING:
"
+
fcgi.QUERY_STRING
+
"
</p>
"
;
s
+=
"
<p>QUERY_STRING_NAMES:
"
+
fcgi.QUERY_STRING_NAMES().到文本()
+
"
</p>
"
;
s
+=
"
<p>QUERY_STRING_UNDECODED:
"
+
fcgi.QUERY_STRING_UNDECODED
+
"
</p>
"
;
s
+=
"
<p>SCRIPT_NAME:
"
+
fcgi.SCRIPT_NAME
+
"
</p>
"
;
s
+=
"
<p>PATH_INFO:
"
+
fcgi.PATH_INFO
+
"
</p>
"
;
s
+=
"
<p>PATH_TRANSLATED:
"
+
fcgi.PATH_TRANSLATED
+
"
</p>
"
;
s
+=
"
<p>REMOTE_ADDR:
"
+
fcgi.REMOTE_ADDR
+
"
</p>
"
;
s
+=
"
<p>REMOTE_HOST:
"
+
fcgi.REMOTE_HOST
+
"
</p>
"
;
s
+=
"
<p>REMOTE_USER:
"
+
fcgi.REMOTE_USER
+
"
</p>
"
;
s
+=
"
<p>REMOTE_IDENT:
"
+
fcgi.REMOTE_IDENT
+
"
</p>
"
;
s
+=
"
<p>AUTH_TYPE:
"
+
fcgi.AUTH_TYPE
+
"
</p>
"
;
s
+=
"
<p>GATEWAY_INTERFACE:
"
+
fcgi.GATEWAY_INTERFACE
+
"
</p>
"
;
s
+=
"
<p>SERVER_NAME:
"
+
fcgi.SERVER_NAME
+
"
</p>
"
;
s
+=
"
<p>SERVER_PORT:
"
+
fcgi.SERVER_PORT.到文本()
+
"
</p>
"
;
s
+=
"
<p>SERVER_PROTOCOL:
"
+
fcgi.SERVER_PROTOCOL
+
"
</p>
"
;
s
+=
"
<p>SERVER_SOFTWARE:
"
+
fcgi.SERVER_SOFTWARE
+
"
</p>
"
;
s
+=
"
<p>DOCUMENT_ROOT:
"
+
fcgi.DOCUMENT_ROOT
+
"
</p>
"
;
s
+=
"
<p>HTTP_ACCEPT:
"
+
fcgi.HTTP_ACCEPT
+
"
</p>
"
;
s
+=
"
<p>HTTP_USER_AGENT:
"
+
fcgi.HTTP_USER_AGENT
+
"
</p>
"
;
s
+=
"
<p>HTTP_REFERER:
"
+
fcgi.HTTP_REFERER
+
"
</p>
"
;
s
+=
"
<p>HTTP_COOKIE:
"
+
fcgi.HTTP_COOKIE
+
"
</p>
"
;
s
+=
"
<p>FCGI_ROLE:
"
+
fcgi.FCGI_ROLE
+
"
</p>
"
;
s
+=
"
<p>FCGI_DATA_LENGTH:
"
+
fcgi.FCGI_DATA_LENGTH.到文本()
+
"
</p>
"
;
s
+=
"
<p>FILE_LAST_MOD:
"
+
fcgi.FILE_LAST_MOD.到文本()
+
"
</p>
"
;
return
s;
}
}
下图是以上程序的执行结果(左图由URL提交,右图由FORM提交(<form action = "cgivars.efcgi" method="post" enctype="multipart/form-data">)),近距离感受它们吧(点击放大图片):
参考:
http://www.fastcgi.com
http://hoohoo.ncsa.uiuc.edu/cgi/
下篇预告:???
一点题外话:上面提到JAVA使用了一个叫 CLASSPATH 的环境变量,我一直觉得这个环境变量的名称取得“太霸道”,你凭什么把这样一个“通用名称”占用了呀,怎么说也该加上一个"JAVA" 或 "J" 前缀吧:JAVA_CLASSPATH, J_CLASSPATH。要不然,后面再出来几个编程语言,也需要使用“类路径”之类的环境变量的话,让人家做何选择?呵呵。相对来说,“易语言.飞扬”就厚道一些,使用了“EF_LIB_PATHS”,加了自己的前缀(EF)。