一.基本原理

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. XPath语法 在C#中使用XPath例子与用法

    XPath可以快速定位到Xml中的节点或者属性.XPath语法很简单,但是强大够用,它也是使用xslt的基础知识.示例Xml: <?xml version="1.0" enc ...

  2. Codeforces Round #467 (Div. 2) B. Vile Grasshoppers[求去掉2-y中所有2-p的数的倍数后剩下的最大值]

    B. Vile Grasshoppers time limit per test 1 second memory limit per test 256 megabytes input standard ...

  3. workflow engine Ruote 安装

    今天在安装gem安装Ruote的过程中遇到问题,改用bundle安装: steven@steven-Latitude-D630:/usr$ sudo mkdir bundel [sudo] passw ...

  4. Working With Push Buttons In Oracle Forms

    Managing push buttons at run time in Oracle Forms is very simple and in this tutorial you will learn ...

  5. 每天学一点Python

    9月11日 1.用List实现Python里的?:条件表达式 ["false","true"][判断条件] 其实就是一个List[0]还是List[1]的问题. ...

  6. Fresco对Listview等快速滑动时停止加载

    Fresco中在listview之类的快速滑动时停止加载,滑动停止后恢复加载: 1.设置图片请求是否开启 // 暂停图片请求 public static void imagePause() { Fre ...

  7. DotnetBrowser入门教程-(3)启动与使用简单的WebSocket服务

    websocket是个很好的通信协议,基本可以贯穿支持html5的所有设备.dotnetbrowser内置了对websocket服务端与客户端的支持.请看例子: 1.新建桌面项目,基于.net 4.0 ...

  8. docker入门小结(一)

    入职需要学习docker,记录学习随笔.争取两天大致看完docker学习.博客也算是迁移到cnblogs. 学习的链接参考<docker从入门到实践>http://dockerpool.c ...

  9. windows的iis做后门,隐藏访问,无日志

    windows下的iis5/iis6做后门,隐藏访问,不留访问记录或者不留日志 好不容易攻下一台Windows2000/2003 IIS服务器,你一定会想,怎样才能长期占有这个“肉鸡”呢?聪明的你肯定 ...

  10. 微信小程序-上传多张图片加进度条(支持预览、删除)

    2018-12-24 详情示例见:https://www.cnblogs.com/cisum/p/9564898.html 2018-12-29 组件下载见:https://www.cnblogs.c ...