Web知识点---公共网关接口CGI的实现方法

介绍

公共网关接口Common Gate Interface,通常简称CGI。下面是百科上面的两句话:

在物理上,CGI是一段程序,它运行在Server上,提供同客户端 Html页面的接口。
绝大多数的CGI程序被用来解释处理来自表单的输入信息,并在服务器产生相应的处理,或将相应的信息反馈给浏览器。

由此总结出了CGI的两个特点

  • 服务器上的可执行程序
  • 处理表单数据,然后反馈给浏览器
    在这里插入图片描述

首先,它是可执行程序,那么自然就有多种方式,结合每个人的开发语言不同,本次介绍了四种语言版本。

  • C语言版本
  • Python版本
  • Shell版本
  • Golang版本
    在这里插入图片描述

然后这个CGI是有输入,有输出的。

方向内容
输入一般就是表单数据
输出一般就是html语言,或者一些指定格式的数据,例如json等

一句话,它就是服务器用来接受浏览器请求,处理数据,返回结果的程序。
在这里插入图片描述

各种语言版本实现方法都是大同小异:

http方法工作方式
GET方法CGI程序就会从环境变量QUERY_STRING中获取数据。
POST方法Web服务器会通过stdin(标准输入)向CGI中传送数据的。而传送的数据长度就是放在ONTENT_LENGTH中的。

模拟了一个配置管理页面。首先介绍一下前端代码,使用的是bootstrap+js实现
在这里插入图片描述

html部分

<div class="container">
	<h1>配置</h1>
	<form class="form-horizontal">
	
	<div class="form-group">
		<label for="text_1" class="col-sm-2 control-label">文本</label>
		<div class="col-sm-5">
		<input type="text" class="form-control" id="text_1" placeholder="文本">
		</div>
	</div>
			
	
	<div class="form-group">
		<label for="select_1" class="col-sm-2 control-label">选择列表</label>
		<div class="col-sm-5">
		<select class="form-control" id="select_1">
		<option value="0">禁用</option>
		<option value="1">启用</option>
		</select>
		</div>
	</div>
				
	<div class="form-group">
		<div class="col-sm-offset-2 col-sm-5">
		<button type="button" class="btn btn-primary" id="bAPPLY">更新</button>
		</div>
	</div>
	</form>
</div>

两个输入,一个提交按钮,利用的ajax方式,所以没有直接form,避免了页面刷新。
在这里插入图片描述

js部分

function page_init()
{
	var gtmstring = {"formname":"formA","action":"get_value","argument":"nul"};
	$.ajax({
			type: "POST",
			url: "/cgi-bin/main.cgi",
			contentType:"application/x-www-form-urlencoded",
			data: gtmstring,
			timeout:5000,
			dataType: "json",
			success: function(msg)
			{
				var all_value = msg.valuelist;
				//alert(all_value);
				var arry_value = all_value.split(",");
				$("#text_1").val(arry_value[0]);
				$("#select_1").val(arry_value[1]); 
			}
		});
}
function page_commit()
{
	if (isEmpty($('#text_1').val()))
	{
		alert("请输入文本");
		return false;
	}
	var gtmstring = "a=" + $("#text_1").val();
	gtmstring += ",b=" + $("#select_1").val();
	var finaldata = {"formname":"formA","action":"set_value","argument":gtmstring};
	$.ajax({
			type: "POST",
			url: "/cgi-bin/main.cgi",
			contentType:"application/x-www-form-urlencoded",
			data: finaldata,
			dataType: "text",
			timeout:5000,
			success: function(msg)
			{ 
				if(msg.indexOf("ok") != -1)
				{
					alert("配置成功!");
				}
				else
				{
					alert("配置失败!");
				}
			}
		});
}

采用的ajax方式提交表单,直接返回结果弹出提示。

那么就分别提供一下各种语言下的一个小例子。

C语言版本

char* getcgidata(FILE* fp, char* requestmethod)
{
	char* input;
	int len;
	int size = 10240;
	int i = 0;

	if (!strcmp(requestmethod, "GET"))
	{
		input = getenv("QUERY_STRING");
		return input;
	}
	else if (!strcmp(requestmethod, "POST"))
	{
		len = atoi(getenv("CONTENT_LENGTH"));
		
		input = (char*)malloc(sizeof(char)*(size + 1));
		if (len == 0)
		{
			input[0] = '\0';
			return input;
		}
		while(1)
		{
			input[i] = fgetc(stdin);
			if (i == size)
			{
				input[i+1] = '\0';
				return input;
			}
			--len;
			if (feof(fp) || (!(len)))
			{
				i++;
				input[i] = '\0';
				return input;
			}
			i++;
		}
	}
	return NULL;
}
int main()
{
    char *input;
    char *req_method;
    char formname[16];
    char action[16];
    char argument[256];
    int i = 0;
    int x = 0;
    int j = 0;

    req_method = getenv("REQUEST_METHOD");
    input = getcgidata(stdin, req_method);

    for ( i =(int)strlen("formname:"); i < (int)strlen(input); i++ )
    {
        if ( input[i] == '&' )
        {
            formname[j] = '\0';
            break;
        } 
        formname[j++] = input[i];
    }

    for ( i = (int)strlen("formname:")+(int)strlen("&action:")+ strlen(formname), j = 0; i < (int)strlen(input); i++ )
    {
        if ( input[i] == '&' )
        {
            action[j] = '\0';
            break;
        } 
    
        action[j++] = input[i];
    }

    strcpy(argument,&input[(int)strlen("formname:")+ (int)strlen(formname)+ (int)strlen("&action:")+(int)strlen(action)+(int)strlen("&argument:")]);
   
    //此处增加自己的操作。

    return 1;
}

这里介绍了核心部分的代码,就是从stdin中,拿到我们需要的表单名称,表单操作,以及传入的参数之后,就可以随意工作了,存入文件,存入数据库,都可以。

Python版本

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# CGI处理模块
import cgi, cgitb 

# 创建 FieldStorage 的实例化
form = cgi.FieldStorage() 

# 获取数据
formname = form.getvalue('formname')
action = form.getvalue('action')
argument = form.getvalue('argument')

print ("Content-Type=text/html;charset=utf-8\n\n")

if formname == 'formA':
	if action == 'get_value':
		print ("{\"valuelist\":\"pythontxt,0\"}")
	else:
		##增加自己的操作处理
		print ("ok")
	

这个是python3.x版本的例子,python中有封装好的cgi模块,提供接口来解析post数据。这一点就很好用。并且python对于数据库及其他方法处理也是各种成熟方案都有,因此是很方便的。
在这里插入图片描述

Shell版本

#!/bin/bash
#test-cgi
 
echo "Content-Type:text/html;charset=utf-8"
echo

#echo SERVER_SOFTWARE = $SERVER_SOFTWARE #服务器软件
#echo SERVER_NAME = $SERVER_NAME         #服务器主机名
#echo GATEWAY_INTERFACE = $GATEWAY_INTERFACE    #CGI版本
#echo SERVER_PROTOCOL = $SERVER_PROTOCOL  #通信使用的协议
#echo SERVER_PORT = $SERVER_PORT         #服务器的端口号
#echo REQUEST_METHOD = $REQUEST_METHOD   #请求方法(GET/POST/PUT/DELETE..)
#echo HTTP_ACCEPT = $HTTP_ACCEPT         #HTTP定义的浏览器能够接受的数据类型
#echo SCRIPT_NAME = $SCRIPT_NAME         #当前运行的脚本名称(包含路径)
#echo QUERY_STRING = $QUERY_STRING       #地址栏中传的数据(get方式)
#echo REMOTE_ADDR = $REMOTE_ADDR         #客户端的ip

if [ "$REQUEST_METHOD" == "POST" ];then
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
        read -n $CONTENT_LENGTH paradata <&0
    fi
elif [ "$REQUEST_METHOD" == "GET" ];then
	paradata=$QUERY_STRING  
fi

para_array=(${paradata//&/ })
formname=${para_array[0]#*=}
action=${para_array[1]#*=}
argument=${para_array[2]#*=}

##echo "{\"valuelist\":\"$action,0\"}"

if [ "$action" == "get_value" ];then
	echo "{\"valuelist\":\"shelltxt,0\"}"
elif [ "$action" == "set_value" ];then
##	此处可以增加自己的操作
	echo "ok"
fi

这个是shell版本,get和post方式都有,这个的方法就很简单了,对于环境的要求不高,能支持bash就可以用,并且无需编译,也是很灵活。
在这里插入图片描述

Golang版本

package main
 
import(
	"fmt"
	"os"
	"bufio"
	"strconv"
	"strings"
)
var inputReader *bufio.Reader
var input string
var err error

func init() {
	fmt.Print("Content-Type=text/html;charset=utf-8\n\n");
}
 
func main() {
	method := os.Getenv("REQUEST_METHOD")
	if method == "POST" {
		var datalen int
		datalen,err = strconv.Atoi(os.Getenv("CONTENT_LENGTH"))

		inputReader = bufio.NewReaderSize(os.Stdin,datalen)
		postdata, _ := inputReader.Peek(datalen)

		parms := strings.Split(string(postdata), "&")
		
		formname := strings.Split(parms[0], "=")
		actions := strings.Split(parms[1], "=")
		argument := strings.Split(parms[2], "=")
		
		if actions[1] == "get_value" {
			fmt.Printf("{\"valuelist\":\"gotxt,0\"}")
		}else if actions[1] == "set_value" {
			/*此处增加操作*/
			fmt.Printf("ok")
		}
	}else if method == "GET" {
		getdata := os.Getenv("QUERY_STRING")
		fmt.Printf("%s",getdata)
	}
}

网上搜索了很久,也没找到cgi这个包怎么用的,只能自己写了一个解析过程,参考的就是前面的编程思想,golang使用的还是少一些,网上文章翻来覆去就那么几篇。可能像我这么用的人太少了吧。
在这里插入图片描述

各种语言比较

  • Shell不挑环境,随时修改调试,适合shell高手
  • Python成熟工具包丰富,接口也很全,用起来很简单,适合新手操作
  • Go语言网上的资料不多,适合想挑战自己的人
  • c语言似乎没什么优势,但是不妨碍它最优秀
    在这里插入图片描述

所有代码下面提供了下载。
下载
代码结构如下
在这里插入图片描述
可以在build.sh中配置使用哪种语言cgi

结尾

真快,又是一周时间过去了,这周没怎么动笔,主要浪费了一些时间来收拾自己的电脑,顺带弄了一个家庭游戏机。
昨天看了谢霆锋的《怒火重案》,大厨多年不演电影了,这次带来的电影还算中规中矩,也让人感慨,香港电影的颓势依旧没办法阻挡,电影中的稍微重要一点的角色,都是大家熟悉的老面孔,大师兄林国斌,渣哥吕良伟,泰国佬卢惠光,当年也是翻来覆去这些人,如今,撑起香港电影的,还是他们,属实挺无奈的。
我们见证了香港电影的辉煌时代,从八十年代开始,成龙的动作片,发哥的警匪片,星爷的无厘头,王晶的……搞笑片。真正的百花齐放。也成了我们童年回忆不可缺少的一部分,那时候小伙伴们聚在一起,看上一部星爷的电影,也是相当的美好。在这里插入图片描述

前几天看到了一个李连杰的动作集锦,也曾感慨,如今的动作片,根本无法再出现李连杰这种奇才了。一方面是传统文化的流失,一方面是生活节奏的加快,各种花瓶偶像,各种综艺选秀,哪里还能有时间再磨炼出一个功夫皇帝。
在这里插入图片描述
电影老了,其实我们的心也在慢慢变老,变得怀旧,变得感性,也变得宽容,变得稳重。前几天孙海洋丢失的儿子找到了,对于父亲来说,这一刻来的太晚了,已经很多年了,多到他儿子已经忘记了他的记忆,很多人说这个儿子不孝,不该替养父母说话,其实我们大可不必这样苛求一个人,突然陷入到这种巨大的家庭变故当中,而能做到客观评判,理性处理,如果能做到,我们反而应该会觉得这个人思想可怕。我们只需要把一切交给时间,当他以后有了自己的孩子,自然就会知道,他父亲坚持那么多年,为的是什么。

在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值