一.基本原理

CGI:通用网关接口(Common Gateway Interface)是一个Webserver主机提供信息服务的标准接口。通过CGI接口,Webserver就行获取client提交的信息。转交给server端的CGI程序进行处理。最后返回结果给client。

组成CGI通信系统的是两部分:一部分是html页面。就是在用户端浏览器上显示的页面。还有一部分则是执行在server上的Cgi程序。

它们之间的通讯方式例如以下图:

server和client之间的通信,是client的浏览器和server端的httpserver之间的HTTP通信。我们仅仅须要知道浏览器请求运行server上哪个CGI程序就能够了,其它不必深究细节。由于这些过程不须要程序猿去操作。

server和CGI程序之间的通讯才是我们关注的。

普通情况下,server和CGI程序之间是通过标准输入输出来进行数据传递的,而这个过程须要环境变量的协作方可实现。

1.    server将URL指向一个应用程序

2.    server为应用程序运行做准备

3.    应用程序运行,读取标准输入和有关环境变量

4.    应用程序进行标准输出

 

对于Windows系统而言。还能够通过profile文件进行传输数据(如ini文件),但在

这里不做研究。

环境变量在CGI中有着重要的地位!

每一个CGI程序仅仅能处理一个用户请求,所以在激

活一个CGI程序进程时也创建了属于该进程的环境变量。

二.环境变量

对于CGI程序来说,它继承了系统的环境变量。CGI环境变量在CGI程序启动时初始化,在结束时销毁。

当一个CGI程序不是被HTTPserver调用时。它的环境变量差点儿是系统环境变量的复制。

当这个CGI程序被HTTPserver调用时,它的环境变量就会多了下面关于HTTPserver、client、CGI传输过程等项目。

与请求相关的环境变量

REQUEST_METHOD

server与CGI程序之间的信息传输方式

QUERY_STRING

採用GET时所传输的信息

CONTENT_LENGTH

STDIO中的有效信息长度

CONTENT_TYPE

指示所传来的信息的MIME类型

CONTENT_FILE

使用Windows HTTPd/WinCGI标准时。用来传送数据的文件名称

PATH_INFO

路径信息

PATH_TRANSLATED

CGI程序的完整路径名

SCRIPT_NAME

所调用的CGI程序的名字

与server相关的环境变量

GATEWAY_INTERFACE

server所实现的CGI版本号

SERVER_NAME

server的IP或名字

SERVER_PORT

主机的port号

SERVER_SOFTWARE

调用CGI程序的HTTPserver的名称和版本

与client相关的环境变量

REMOTE_ADDR

客户机的主机名

REMOTE_HOST

客户机的IP地址

ACCEPT

例出能被次请求接受的应答方式

ACCEPT_ENCODING

列出客户机支持的编码方式

ACCEPT_LANGUAGE

表明客户机可接受语言的ISO代码

AUTORIZATION

表明被证实了的用户

FORM

列出客户机的EMAIL地址

IF_MODIFIED_SINGCE

当用get方式请求而且仅仅有当文档比指定日期更早时才返回数据

PRAGMA

设定将来要用到的server代理

REFFERER

指出连接到当前文档的文档的URL

USER_AGENT

client浏览器的信息

CONTENT_TYPE:如application/x-www-form-urlencoded,表示数据来自HTML表单,而且经过了URL编码。

ACCEPT:客户机所支持的MIME类型清单。内容如:”image/gif,image/jpeg”

REQUEST_METHOD:它的值一般包含两种:POST和GET,但我们写CGI程序时,最后还要考虑其它的情况。

1.POST方法

假设採用POST方法。那么client来的用户数据将存放在CGI进程的标准输入中,同一时候将用户数据的长度赋予环境变量中的CONTENT_LENGTH。client用POST方式发送数据有一个对应的MIME类型(通用Internet邮件扩充服务:Multi-purpose
Internet Mail Extensions)。眼下,MIME类型通常是:application/x-wwww-form-urlencoded,该类型表示数据来自HTML表单。

该类型记录在环境变量CONTENT_TYPE中,CGI程序应该检查该变量的值。

2.GET方法

在该方法下,CGI程序无法直接从server的标准输入中获取数据,由于server把它从标

准输入接收到得数据编码到环境变量QUERY_STRING(或PATH_INFO)。

GET与POST的差别:採用GET方法提交HTML表单数据的时候。客户机将把这些数

据附加到由ACTION标记命名的URL的末尾,用一个包含把经过URL编码后的信息与CGI程序的名字分开:http://www.mycorp.com/hello.html?name=hgq$id=1。QUERY_STRING的值为name=hgq&id=1

有些程序猿不愿意採用GET方法,由于在他们看来,把动态信息附加在URL的末尾有

违URL的出发点:URL作为一种标准用语。通常是用作网络资源的唯一定位标示。

环境变量是一个保存用户信息的内存区。

当client的用户通过浏览器发出CGI请求时,server就寻找本地的对应CGI程序并运行它。

在运行CGI程序的同一时候,server把该用户的信息保存到环境变量里。

接下来,CGI程序的运行流程是这种:查询与该CGI程序进程对应的环境变量:第一步是request_method,假设是POST,就从环境变量的len,然后到该进程对应的标准输入取出len长的数据。

假设是GET。则用户数据就在环境变量的QUERY_STRING里。

3.POST与GET的差别

以 GET 方式接收的数据是有长度限制,而用 POST 方式接收的数据是没有长度限制的。

而且。以 GET 方式发送数据,能够通过 URL 的形式来发送,但 POST方式发送的数据必需要通过 Form 才到发送。

三.CGI程序实现步骤

1.从server获取数据

C语言实现代码:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

int get_inputs()

{

int length;

char *method;

char *inputstring;

method = getenv(“REQUEST_METHOD”); //将返回结果赋予指针

if(method == NULL)

return 1;       //找不到环境变量REQUEST_METHOD

if(!strcmp(method, ”POST”))  // POST方法

{

length = atoi(getenv(“CONTENT_LENGTH”)); //结果是字符,须要转换

if(length != 0)

{

inputstring = malloc(sizeof(char)*length + 1) //必须申请缓存。由于stdin是不带缓存的。

fread(inputstring, sizeof(char), length, stdin); //从标准输入读取一定数据

}

}

else if(!strcmp(method, “GET”))

{

Inputstring = getenv(“QUERY_STRING”);

length = strlen(inputstring);

}

if(length == 0)

return 0;

}

Perl实现代码:

$method = $ENV{‘REQUEST_METHOD’};

if($method eq ‘POST’)

{

Read(STDIN, $input, $ENV{‘CONTENT_LENGTH’});

}

if($method eq ‘GET’ || $method eq ‘HEAD’)

{

$input = $ENV{‘QUERY_STRING’};

}

if($input eq “”)

{

&print_form;

exit;

}

PYTHON代码实现

#!/usr/local/bin/python

import cgi

def main():

form = cgi.FieldStorage()

Python代码实现更简单,cgi.FieldStorage()返回一个字典,字典的每个key就是变量名,key相应的值就是变量名的值。更本无需用户再去进行数据解码!

获取环境变量的时候,假设先推断“REQUEST_METHOD”是否存在,程序会更健壮,否则在某些情况下可能会造成程序崩溃。

由于假若CGI程序不是由server调用的,那么环境变量集里就没有与CGI相关的环境变量(如REQUEST_METHOD。REMOTE_ADDR等)加入进来,也就是说“getenv(“REQUEST_METHOD”)”将返回NULL。

2.URL编码

无论是POST还是GET方式,client浏览器发送给server的数据都不是原始的用户数据,而是经过URL编码的。此时。CGI的环境变量Content_type将被设置,如Content_type
= application/x-www-form-urlencode就表示server收到的是经过URL编码的包括有HTML表单变量数据。

编码的基本规则是:

变量之间用“&”分开;

变量与其相应值用“=”连接。

空格用“+”取代。

保留的控制字符则用“%”连接相应的16禁止ASCII码取代;

某些具有特殊意义的字符也用“%”接相应的16进制ASCII码取代。

空格是非法字符;

随意不可打印的ASCII控制字符均为非法字符。

比如,如果3个HTML表单变量filename、e-mail和comments,它们的值相应分别为hello、mike@hotmail.com和I’ll
be there for you,则经过URL编码后应为:

filename=hello&e-mail=hello@hotmail.com&comments=I%27ll+be+there+for+you

所以,CGI程序从标准输入或环境变量中获取client数据后,还须要进行解码。

解码的过程就是URL编码的逆变:依据“&”和“=”分离HTML表单变量,以及特殊字符的替换。

在解码方面,PYTHON代码实现是最理想的,cgi.FieldStorage()函数在获取数据的同一时候就已自己主动进行代码转换了,无需程序猿再进行额外的代码编写。Perl其次,由于在一个现成的Perl库:cgi-lib.pl中提供了ReadParse函数,用它来进行URL解码非常easy:

require ‘cgi-lib.pl’;

&ReadParse(*input);

3.CGI数据输出

CGI程序怎样将信息处理结果返回给client?这实际上是CGI格式化输出。

在CGI程序中的标准输出stdout是经过重定义了的,它并没有在server上产生不论什么的输出内容。而是被重定向到客户浏览器,这与它是由C。还是Perl或Python实现无关。

所以,我们能够用打印来实现client新的HTML页面的生成。

比方,C的printf是向该进程的标准输出发送数据,Perl和Python用print向该进程的标准输出发送数据。

(1)    CGI标题

CGI的格式输出内容必须组织成标题/内容的形式。CGI标准规定了CGI程序能够使用

的三个HTTP标题。

标题必须占领第一行输出!

并且必须随后带有一个空行。

标题

描写叙述

Content_type   (内容类型)

设定随后输出数据所用的MIME类型

Location    (地址)

设定输出为另外一个文档(URL)

Status      (状态)

指定HTTP状态码

MIME:

向标准输出发送网页内容时要遵守MIME格式规则:

随意输出前面必须有一个用于定义MIME类型的输出内容(Content-type)行。并且随后还必须跟一个空行。假设遗漏了这一条,服务将会返回一个错误信息。

(相同使用于其它标题)

比如Perl和Python:

print “Content-type:text/html\n\n”;   //输出HTML格式的数据

print “<body>welcome<br>”

print “</body>”

C语言:

printf( “Content-type:text/html\n\n”);

printf(“Welcome\n”);

MIME类型以类型/子类型(type/subtype)的形式表示。

当中type表示一下几种典型文件格式的一种:

Text、Audio、Video、Image、Application、Mutipart、Message

Subtype则用来描写叙述详细所用的数据格式。

Application/msword

微软的Word文件

Application/octet-stream

一种通用的二进制文件格式

Application/zip

Zip压缩文件

Application/pdf

Pdf文件

。。

。。。。

。。。。

。。

。。

。。

。。。。。

。。。。

。。。

。。。

。。。。。。。。。。。

。。

Location:

使用Location标题。一个CGI能够使当前用户转而訪问同一server上的另外一个程序,甚至能够訪问另外一个URL,但server对他们的处理方式不一样。

使用Location的格式为:Location:Filename/URL,比如:

print “Location:/test.html\n\n”;

这与直接链接到test.html的效果是一样的。

print “Location:http://www.chinaunix.com/\n\n”

因为该URL并不指向当前server,用户浏览器并不会直接链接到指定的URL。而是给用户输出提示信息。

HTTP状态码:

表示了请求的结果状态。是CGI程序通过server用来通知用户其请求是否成功运行的信息码,本文不做研究。

四.CGI中的信号量和文件锁

因为CGI程序时公用的,而WEBserver都支持多进程执行,因此可能会发生同一时候有多个用户訪问同一个CGI程序的情况。比方,有2个用户差点儿同一时候訪问同一个CGI程序,server为他们创建了2个CGI程序进程。设为进程A和进程B。假如进程A首先打开了某个文件,然后因为某种原因被挂起(通常是因为操作系统的进程调度)。而就在进程A被挂起的这段时间内,进程B完毕了对文件的整个操作流程:打开。写入。关闭;进程A再继续往下执行,但进程A所操作的文件依然是原来文件的就版本号,此时进程A的操作结果将覆盖进程B的操作结果。

为了防止这样的情况发生,须要用到文件锁或者信号量。

钥匙文件?

假如有多个不同的HTML能够调用同一个CGI程序,那么CGI程序怎样区分它们呢?一个是通过隐含的INPUT标签。

只是认为这个比較麻烦,由于CGI必须经过一系列解码后才干找到这个隐含INPUT的变量和其值。

五.设置HTTPserver以兼容CGI

用Perl编写的CGI程序后缀为:.pl;Python编写的CGI程序后缀为:.py;而C编写的CGI程序后缀为:.cgi。假设在win下编译出来的是.exe,最好将它重命名为.cgi。这些都是为了HTTP服务可以识别并调用它们。

当使用appche httpdserver时。请编辑它的配置文件httpd.conf例如以下:

改动AddHandler cgi-script一句为AddHandler
cgi-script .cgi .py .pl

六.关于CGI的C语言库——cgihtml

Cgihtml是一个应用很广泛的C语言编写的CGI库。

它提供的功能函数例如以下:

Read_cgi_input():获取并解析HTML表单输入,返回一个指向某结构体的指针

Cgi_val():获取每一个表单变量的值

Html_header():输出HTML标题栏

Html_begin():输出HTML文档的開始部分

H1():输出一行字符,字体为H1

Html_end():输出HTML文档的结尾部分。

#include “cgi-lib.h”

#include “html-lib.h”

#include “string-lib.h”

六.后话

有的人觉得能够用JavaScript来代替CGI程序,这事实上是一个概念上的错误。

JavaScript仅仅能够在客户浏览器中执行,而CGI却是工作在server上的。

他们所做的工作有一些交集。比方表单数据验证一类的。可是JavaScript是绝对无法代替CGI的。但能够这样说,假设一项工作即能够用JavaScript来做,又能够用CGI来做,那么绝对要使用JavaScript,在执行的速度上,JavaScript比CGI有着先天的优势。

仅仅有那些在client解决不了的问题,比方和某个远程数据库交互。这时就应该使用CGI了。

SSI:一种用来动态输出HTML文本的特殊程序。

网页里包括有某个变量,提交给server后,仅仅有该变量改变。此时我们希望server不要把整个页面内容都发送过来,而仅仅须要告诉client的浏览器,哪个变量的值便成什么样了,浏览器会自己主动更新。

SSI在server端执行。

SSI不须要外部接口,它不像CGI从标准输入接收信息。

你浏览你的HTML文档时看不到SSI标记,由于它已经被对应的程序输出所替代。

全部的SSI命令都是嵌入在普通的HTML凝视行中的。当server无法解释SSI时,它将不解释并直接把文档传给浏览器。因为命令在凝视中,故浏览器将忽略它们。

而当server识别SSI时。它并不将该命令传给浏览器,相反,server将从上到下扫描HTML文档,运行每个嵌入凝视的命令,并将命令的运行结果取代原凝视。

<! –凝视文本-- >。server将根本不查看凝视,除非已启动SSI。

与纯凝视不同的是,全部的SSI命令都是以#打头。

<! --#command tagname = “parameter”-- >,command指出server做什么,tagname指出參数类型,parameter是该命令的用户定义值。

The current date is<! --#echo var = “DATE.LOCAL”-- >,server将向浏览器输出时间。

CGI的基本原理的更多相关文章

  1. CGI技术原理

    一.CGI技术 1.1 CGI的提出 CGI是外部扩展应用程序与WWW服务器交互的一个标准接口.按照CGI标准编写的外部扩展应用程序可以处理客户端(一般是WWW浏览器)输入的协同工作数据,完成客户端与 ...

  2. Linux 高性能server编程——高级I/O函数

    重定向dup和dup2函数 #include <unistd.h> int dup(int file_descriptor); int dup2(int file_descriptor_o ...

  3. jsp学习第一弹

    早期动态网站开发技术主要使用cgi技术,cgi的基本原理是,将浏览器提交至web服务器的数据通过环境变量传递给其他外部程序,经外部程序处理后,再由cgi把处理结果传送给web服务器,最后由web服务器 ...

  4. Linux 高性能服务器编程——高级I/O函数

    重定向dup和dup2函数 #include <unistd.h> int dup(int file_descriptor); int dup2(int file_descriptor_o ...

  5. 说说Java Web中的Web应用程序|乐字节

    大家好,我是乐字节的小乐,今天接着上期文章<Javaweb的概念与C/S.B/S体系结构>继续往下介绍Java Web ,这次要说的是web应用程序. 1. Web 应用程序的工作原理 W ...

  6. 服务器CGI运行机制

    CGI概括: 定义 通用网关接口(Common Gateway Interface)是HTTP服务器与你的或其它机器上的程序进行"交谈"的一种工具,其程序须运行在网络服务器上. 功 ...

  7. 【转】初识CGI

    一.基本原理 CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口.通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器 ...

  8. cgi表单的处理

    在HTML中,当客户填写了表单,并按下了发送(submit)按钮后,表单的内容被发送 到了服务器端,一般的,这时就需要有一个服务器端脚本来对表单的内容进行一些处理, 或者是把它们保存起来,或者是按内容 ...

  9. CGI编程完全手册

    一.基本原理 CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口.通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器 ...

随机推荐

  1. 和菜鸟一起学android4.0.3源码之lcd屏幕背光调节

    周六的中午还是依旧来了公司,本来也没有打算来的,既然来了,那就把上次遗留下来的一些问题给解决吧,把android下的pwm调lcd背光给总结下吧.关于android的背光,是用pwm波来控制的,通过占 ...

  2. (5)php数组

    定义数组 $arr=array('篮球','自行车','海贼王'); 打印指定数组 echo $arr[0]; 打印全部数组 print_r($arr); 改变数组的值 $arr[0]='足球'; 赋 ...

  3. 使用TensorFlow 来实现一个简单的验证码识别过程

    本文我们来用 TensorFlow 来实现一个深度学习模型,用来实现验证码识别的过程,这里识别的验证码是图形验证码,首先我们会用标注好的数据来训练一个模型,然后再用模型来实现这个验证码的识别. 1.验 ...

  4. dedecms跳转标签

    我们在使用织梦dedecms制作网站的时候,有时会遇到利用arclist和list标签调用redirecturl属性.但是,dedecms的arclist和list标签不支持redirecturl.很 ...

  5. java.io.IOException: Cannot run program "java" (in directory "/data01/var/lib/jenkins/workspace/2540cb62a866eda983ab8cba34fcd4f9"): error=2, No such file or directory

    通过下图所示方式,可以在同一台机器上启动多个jenkins slave 执行项目的时候报错: 解决办法:首先排查,目标文件或者目录是否存在,如果存在,则在目录机器添加/usr/bin/java的软链接 ...

  6. Geographical distance

    Introduction Calculating the distance between geographical coordinates is based on some level of abs ...

  7. 第1章 为什么创造WPF、第2章 XAML揭秘

    1.2 步入WPF 下面是WPF的一些亮点: 广泛整合:各种媒体类型都能组合起来并一起呈现 与分辨率无关:因为WPF使用矢量图形 硬件加速:WPF是基于Direct3D创建的,工作全部是由GPU完成的 ...

  8. Linux下的定时任务Crontab

    通过crontab -e写入定时任务的指令,一行为一项任务. 任务模式是时间克龙表达式+命令形式. 如: 2 0,6,12,18 * * * perl /root/restarttomcat.pl p ...

  9. /etc/shadow 密码加密方法

    [root@mysql-master ~]# cat /etc/shadowroot:$6$spzQDWctb8Lmju0o$KoUz5Qwv1tWyVYfd5cuBw.TQVIaCvCX8ixGG9 ...

  10. MSComm串口类的使用 (程序设计)

    参考文档:http://wenku.baidu.com/link?url=MLGQojaxyHnEgngEAXG8oPnISuM9SVaDzNTvg0oTSrrJkMXIR_6MR3cO_Vnh-gr ...