java编写cgi_编写CGI⼩结(Java)
由于Carl要⽤到我的程序,我们便合作⼯作。但是他写的程序是Python的,我写的程序是Java的,必须得⼀种⽅式进⾏通信。尽管有Jython这些东西,但是Carl认为还是CGI最简便。于是,前阵⼦开始学学CGI怎么弄。刚开始,觉得好像也不是很难,但是后来进展没有预期的顺利。最后,由于学院的服务器有CGI模块但是不允许随便跑CGI,实验室服务器⼜装的是FastCGI,感觉⿇烦,最后Carl说还是⽤socket吧... - - |||。
整体来说,⽤CGI进⾏通信这个计划算是破产了。虽然是很⽼旧、基本都不会再⽤的东西了,但是由于对我来说是新东西,还是很好奇,没有实现,⾃然是⼀种惋惜。虽然最后没能⽤上CGI,但是个⼈觉得如果学院服务器让⽤户⾃⼰跑CGI的话,应该还是没问题的。⽆论怎样,还是记录下⼀些基本知识,免得以后⼜忘了。
CGI年代久远,不过却实现了动态⽹页。CGI,准确说,应该是种协议(或者说接⼝),它使得server中的程序(cgi script)能够通过标准I/O流(STDIN和STDOUT,⽐如在Java语⾔⾥就是System.in和System.out,在C⾥⾯就是printf等,只要是能够进⾏标准I/O流读写的程序,都可以⽤来实现CGI)读取到所需的信息和输出信息给浏览器,⽽这些所要从客户端读取的信息则是包含在某些已经被定义好的环境变量中,我们只需要读取这些环境变量,⾃然就能获取想要的值了(这也就是CGI这个借⼝为我们所做的
事)。⽽通常所说的CGI,也有可能泛指CGI程序,即CGI script,是开发者⾃⼰所写的、处理⽤户请求的程序。
总体来说,过程是这样的:
1. 服务器接受到请求
2. 服务器发现这个请求是需要⼀个CGI程序来进⾏处理
3. 服务器建⽴⼀个环境,这个运⾏环境⾥有⼀些变量,也就是所谓的CGI程序所需要的环境变量
4. 服务器在这个环境下启动相应的CGI程序
5. CGI程序解析⾃⼰想要的环境变量来获取所提交的请求信息
6. CGI程序对这些请求信息做相应的处理
7. CGI程序将相应的结果输出到标准输出STDOUT,此结果将被输出到⽤户端,呈现给⽤户结果。
8. CGI程序执⾏完毕,退出程序。
⽐较详细来说,原理⼤概是这样的:
1. 客户端在浏览某个⽹页的时候,提交表单(form)。⽽表单的action则指定了要处理该表单的CGI程序,⽐如:
上⾯的程序中,action="/i" 的意思就是说“这个表单⾥的数据,都交给i这个程序处理了,然后它处理完这些数据后,再把结果返回给浏览器”。
需要说明的是,plus是⼀个可执⾏⽂件的⽂件名,⽐如可能是⼀个shell⽂件(例如 plus.sh),其后缀不⼀定是.cgi。那么为什么要取在这⾥取名.cgi呢?原因是这样能说明,这个表单处理,是通过⼀个类型为cgi的程序进⾏处理,或者说,通过cgi这种⽅式让这个可执⾏⽂件对提交的数据进⾏处理。⼀般来说,出于安全考虑,不是任何⽤户都有权限去写⼀个⾃⼰的cgi程序然后上传到服务器、让该服务器去运⾏的(⽐如我们学院的服务器就不⾏,哎...)。⽽只有放在服务器指定⽬录(⼀般为cgi-bin)下的可执⾏⽂件,才会被被视为是cgi程序,才能被执⾏。⽽⼀般⼈是⽆法访问这个⽬录的。
2. 然后,name为“m”和“n”的这两个变量以及他们的值,就通过某个环境变量输⼊到CGI程序中,由CGI程序去进⾏该CGI程序所指定的处理了。GET和POST获取“m”和“n”的⽅式有所不同。如果提交⽅法是GET的话,那么GET所提交的内容则被包含在名为
QUERY_STRING的环境变量中,当得到这个环境变量的值后,将其内容解析出来就可以得到name/value这样的值对了,就可以进⾏相应的处理了。⽽POST的话,则需要从标准输⼊流STDIN⾥
⾯读取数据,⽽这些数据到底有多少呢?这个则需要通过读取
CONTENT_LENGTH这个环境变量的值来知道。
像在C语⾔⾥⾯,可以通过getenv函数来直接获取环境变量的值,⽐如:getenv("QUERY_STRING"), getenv("CONTENT_LENGTH")等等。Perl可能要算是写CGI的最佳语⾔,但是不会Perl,此处略过。另外,由于我的程序是⽤Java写的,就使得读取环境变量的⽅式有点特殊,因为Java是没有直接获取这些环境变量的函数的。Java为何不能直接访问环境变量?简单说,因为Java内部还有⼀个属于System这个类的属性。因此,我们⼀个Property获取的是Java中这个System类的属性的,⽽不是环境变量的。这些System的属性也是以name/value这样的形式来存储⼀些Java运⾏环境的信息的。因⽽,额外的环境变量(或者说属性信息)需要⽤指令java -D的形式,详见后⾯的wrapper程序。
常⽤的环境变量有:REQUEST_METHOD,QUERY_STRING,CONTENT_LENGTH,PATH_INFO。其他的有:
SERVER_SOFTWARE,SERVER_NAME,GATEWAY_INTERFACE,SERVER_PROTOCOL,SERVER_PORT,PATH_TRANSLATED,S 如果现在忘记这些是⼲嘛的了...额...google下吧...
如何解析这些⿇烦的字符串,不需要⾃⼰再动⼿去写,⽹上有很多这样的函数库,各种语⾔。直接⽤⽹上现成的函数库来解析就⾏了。就
Java来说,推荐cgi_lib.java这个库。很⽅便,应⽤也很⼴泛,⽂件也很⼩。其中函数的功能是跟cgi_lib.pl⼀样的。
3. 解析字符串后,我们可以知道变量m的值为5,变量n的值为6。然后就可以在CGI程序中进⾏相应的处理了。⾃⼰想怎么处理就怎么处
理。⽐如,此处是想处理加法,则在⾃⼰的CGI程序⾥实现m和n的加法即可。
4. 处理完了数据,需要将结果呈现给浏览器端的⽤户。这个简单,直接⽤STDOUT就⾏了。⽐如,C语⾔⽤printf,Java语⾔⽤
System.out.println之类的。但是需要注意的是,⾸先输出的必须是"Content-type: text/plain"(也就是MIME头信息,告诉server它随后
的输出是以纯ASCII⽂本的形式),然后下⾯空⼀⾏(必须空⼀⾏),再直接打印出要呈现给⽤户的html语句。⽐如,在Java⾥⾯,就是:
System.out.println("Content-type: text/plain");
System.out.println("");
⽐如,要测验⾃⼰是否有权限可以写⼀个CGI放在服务器上运⾏,则可以写⼀个最简单的CGI程序,该程序暂时不处理任何来⾃⽤户的请
求,只是输出"Hello, world"。
shell程序可以写成:
#!/bin/sh
echo "Content-type: text/html"
echo ""
echo ""
echo "
"
echo "
Hello, world
"
echo ""
echo ""
C语⾔可以写成:
#include
void main(void){
printf("Content-type: text/html\n");
printf("\n");
printf("\n");
printf("
\n");
printf("
Hello, world
\n");
printf("");
printf("/");
}
这样,在客户端运⾏就会呈现出
⼤⼩的“Hello, world”了。
Java的特别注意:
1.Java读取环境变量,只能通过-D的option来加以读取。
2.Java⽣成的.class⽂件(⽐如java_plus.class),这不是⼀个通常意义上的可执⾏⽂件,这个⽂件只是说通过JVM可以执⾏起来。⽽CGI程序是⼀个直接可以执⾏的⽂件。因此,我们需要写⼀个wrapper,将这个.class⽂件封装起来。当调⽤这个wrapper程序的时候,这个wrapper程序能通过Java指令运⾏该.class⽂件。
结合上诉两点,则我们可以写⼀个shell⽂件当做wrapper程序,如下:
#!/bin/sh
java \
-t_type=$CONTENT_TYPE \
-t_length=$CONTENT_LENGTH \
-quest_method=$REQUEST_METHOD \
-Dcgi.query_string=$QUERY_STRING \
-Dcgi.server_name=$SERVER_NAME \
-
Dcgi.server_port=$SERVER_PORT \
-Dcgi.script_name=$SCRIPT_NAME \
-Dcgi.path_info=$PATH_INFO \
java_plus
然后将上⾯的⽂件保存为plus.sh,并且放在指定的⽬录(⽐如cgi-bin)即可。这样,当表单提交新的时候,就会到这个⽬录中(因为后缀名为cgi)去寻名为plus的⽂件,然后执⾏这个⽂件。⽽在java_plus这个⽂件中,我们⽤Property("cgi.query_string")就可以访问到QUERY_STRING这个环境变量了。
perl是用来干嘛的推荐⼀些链接:
⾄于FastCGI,这个效率⽐传统CGI⾼很多。但是,⽐较⿇烦,需要⽤循环,还要设置端⼝什么的,就没动⼿搞那个,只是看了下相关资料。还是放在这⾥吧。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论