一、背景说明

虽然很久以前就听说“早期的网站很多通过cgi形式实现”、“C++可通过CGI形式编写网页”,日积月累对CGI也有了一些概念,但一直没真正见过一个实际运行的CGI网站,总归还是有些底气不足。

上周在菜鸟教程上看到有CGI的编程实现所以就模仿实现一下,而过程中发现不能成功运行(其实是自己的未指定脚本处理shell的问题),然后又百度其他资料看到实现方式五花八门不是人云亦云就是实现很不规范,所以自己记录一下。

本文实现环境:Ubuntu 16.04 + Python 3.7 + apache2

二、Ubuntu上的apache2配置

2.1 apache2配置文件形式

Ubuntu(严谨点应该说Dibian)上apache的配置文件在/etc/apache2的目录,我们先来看其目录结构,如下:

xxx-available文件夹表示当前apache2支持的功能,对应的xxx-enabled表示启用的功能;xxx-enabled下的文件一般是xxx-available下的文件的软链接。

其中magic定义的是一些MIME的东西(?),envvars定义一些供其他配置文件使用的变量,这两个一般不用我们修改来看我们需要修改的:

/etc/apache2/
|-- apache2.conf # 该文件通过IncludeOptional包含以下(各目录中的)配置文件
| `-- ports.conf # 该文件主要配置监听端口
|-- mods-enabled # 该目录下的文件是针对某个模块的配置
| |-- *.load # .load文件一般是用LoadModule命令加载模块对应的.so文件
| `-- *.conf # .conf文件一般是同名.load文件加载的模块的本身需要的配置,一般不用我们管
|-- conf-enabled # 该目录下的文件一般是针对某项功能的配置
| `-- *.conf
`-- sites-enabled # 该目录下的文件用于配置VirtualHost
`-- *.conf

apache被分成这么多配置文件,是为了让我们方便地知道某项功能对应的配置功是什么;当然对于不熟悉的人则可能感觉到的不是方便而是复杂,此时就要知道这只是一种约定的组织形式而并不是语法上的强制,所以你要所有配置全都一把写在apache2.conf这文件中也是可以的(但注意apache2为先配置先生效后配置不生效原则,如果IncludeOptional在前且已配置某项的值那你在apache2.conf追加的该项值会不生效)。

2.2 apache2启停功能配置操作

从上节的介绍中,我们可以总结出想启用某项功能就在xxx-enabled目录下,创建指向该功能在xxx-available目录下相应文件的软链接;要停用某项功能就删除该功能在xxx-enable目录下相应的软链接。

这操作是可行的,但Ubuntu还直接提供了命令来实现该功能,这可以免除我们切换目录、忘记软链接命令书写格式、遗漏链接等困挠。

mod对应的启停用使令是a2enmod/a2dismod,conf对应的启停用命令是a2enconf/a2disconf,site对应的启停用命令是a2ensite/a2dissite。

比如我们这里想启用停用cgi支持功能对应的命令就是:

# cgi和cgid这两个模块的区别是什么我还不太懂,似乎其实只用cgid就可以了(?)
# 启用,cgi、cgid这两个名字是mods-available目录下的文件的名字
sudo a2enmod cgi cgid
# 停用,cgi、cgid这两个名字是mods-enabled目录下要删除掉的软链接的名字
sudo a2dismod cgi cgid

可能有小伙伴还是感觉没有很方便啊,我还是得到mods-available或mods-enabled下看文件的名字;那其实还有另外的写法,你可以先不带要启用/停用的功能的名字,然后该命令就会列出当前所有可启用/停用的功能的名字,此时你再输入想要启用/停用的功能的名字即可,如下图:

三、Python3 CGI编程实现

3.1 apache2配置支持cgi

总结第二大节知识,使用以下命令启用:

# 启用模块支持。还是那句话我暂时没懂cgi和cgid的区别,所以索性两个都启用
sudo a2enmod cgi cgid
# 启用cgi的默认配置。
sudo a2enconf serve-cgi-bin
# 重启apache使用置生效
sudo systemctl restart apache2

3.2 针对性改造

这里的针对性改造指两点,一是我们前面只是启动了cgi我们还没给apache指出要处理什么语言的cgi,二是我们想指定cgi文件的目录为/var/www/cgi-bin。

我们先到/etc/apache2/conf-enabled目录下查看serve-cgi-bin.conf的配置,默认如下:

<IfModule mod_alias.c>
<IfModule mod_cgi.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule> <IfModule mod_cgid.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule> <IfDefine ENABLE_USR_LIB_CGI_BIN>
ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
</IfDefine>
</IfModule> # vim: syntax=apache ts=4 sw=4 sts=4 sr noet

可以看到一是没有配置处理文件,二是设置的文件夹是/usr/lib/cgi-bin/。我们使用"AddHandler cgi-script .cgi .py"指定cgi指定扩展名为.cgi和.py的文件(一般不管什么语言写的都应保存成.cgi但对于pytho也允许保存成习惯的.py),另使用“ScriptAlias /cgi-bin/ /var/www/cgi-bin/”指定遇到路径为“/cgi-bin/”的url就转向“/var/www/cgi-bin/”目录下找文件,最终修改如下:

<IfModule mod_alias.c>
<IfModule mod_cgi.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule> <IfModule mod_cgid.c>
Define ENABLE_USR_LIB_CGI_BIN
</IfModule> <IfDefine ENABLE_USR_LIB_CGI_BIN>
ScriptAlias /cgi-bin/ /var/www/cgi-bin/
<Directory "/var/www/cgi-bin/">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
AddHandler cgi-script .cgi .py
</Directory>
</IfDefine>
</IfModule> # vim: syntax=apache ts=4 sw=4 sts=4 sr noet

3.3 python文件编写

注意两点:

一是开头的#!指定文件解析shell不可少且shell要改成自己python所在路径(否则报错“End of script output before headers:”),因为我们虽然指定了cgi处理.py文件,但本质上apache还是不懂.py应该使用哪个shell去处理.py文件。

二是大多数教程都是上来直接写print(),我这里特地写成了一个方法的形式,主要是为了强调cgi最终就是python helloworld.py这么运行的,你最终输出一个html响应就行,并不需要你上来就print()。

# 创建/var/www/cgi-bin/目录
sudo mkdir /var/www/cgi-bin/
# 创建helloworld.py文件并写入内容
# 我不清楚为什么sudo直接cat写入会提示Permission denied所以搞这么麻烦
sudo touch /var/www/cgi-bin/helloworld.py
sudo chmod 777 /var/www/cgi-bin/helloworld.py
sudo cat > /var/www/cgi-bin/helloworld.py << EOF
#!/opt/miniconda3/bin/python def main():
print ("Content-type:text/html")
print () # 空行,告诉服务器结束头部
print ('<html>')
print ('<head>')
print ('<meta charset="utf-8">')
print ('<title>Hello Word - My First CGI Programe !</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word! This is my first CGI programe !</h2>')
print ('</body>')
print ('</html>') main()
EOF
# 如果自使使用vi写入的文件那么写完后记得给文件添加可执行权限

3.4 运行效果演示

由于在前边做了很多配置,为了以防万一建议在访问前重启一把apache:

sudo systemctl restart apache2

运行效果如下:

3.5 运行过程分析【可选】

请求-响应数据包过程如下:

我们在/var/www/cgi-bin目录下新建一个error.py文件,写入以下内容并保存(主要是没有指定shell那一行运行会报错):

def main():
print("Content-type:text/html")
print() # 空行,告诉服务器结束头部
print('<html>')
print('<head>')
print('<meta charset="utf-8">')
print('<title>Hello Word - My First CGI Programe !</title>')
print('</head>')
print('<body>')
print('<h2>Hello Word! This is my first CGI programe !</h2>')
print('</body>')
print('</html>') main()

重启apache后访问两次error.py页面两次,然后查看错误日志(默认是/var/log/apache2/error.log)末尾的内容,如果没有意外应该是如下的两个报错;报错没有什么问题,问题是我们可以看到两次访问报错的进程id是不一样的,这就认证了cgi每次都重新启动一个进程的说法(本质差不多和自己手动运行python文件差不多)。

四、C++ CGI编程实现【可选】

应该来说到上一大节我们的内容已经都讲完了,但一方面python是一种解析型语言到C++等编译型语言是不是一样总还是不敢确定,另一方面按网上的说法C++对apache的配置完全和python一样,在已有环境还是比较容易实现所以我们来看一下。

第一步,在/var/www/cgi-bin目录创建cplusplus.cpp文件、添加可执行权限、写入以下内容:

#include <iostream>
using namespace std; int main ()
{ cout << "Content-type:text/html\r\n\r\n";
cout << "<html>\n";
cout << "<head>\n";
cout << "<title>Hello World - First CGI Program</title>\n";
cout << "</head>\n";
cout << "<body>\n";
cout << "<h2>Hello World! This is my first CGI program</h2>\n";
cout << "</body>\n";
cout << "</html>\n"; return ;
}

第二步,使用g++进行编译(不能使用gcc不然会因gcc不会自动链接c++库而报错“cplusplus.cpp:(.text+0xa): undefined reference to `std::cout'”)并把输出文件后辍名指定为.cgi。

sudo g++ -o cplusplus.cgi cplusplus.cpp

由于编译成了可执行文件所以cpp文件不用指定解析器语句也就很好理解了,直接执行输出如下(所以我们是否可以认为web的本质就是中间件把程序输出返回到前端?):

第三步,访问页面确认效果。如下图:

参考:

https://www.runoob.com/python3/python3-cgi-programming.html

https://www.tutorialspoint.com/cplusplus/cpp_web_programming

Python3 CGI编程实现教程的更多相关文章

  1. Python3 CGI编程

    什么是CGI CGI 目前由NCSA维护,NCSA定义CGI如下: CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户 ...

  2. Python的CGI编程实现-通过接口运行服务器py脚本

    yum 安装apcche [apache]yum 安装Apache(Centos 6.9) https://www.cnblogs.com/lauren1003/p/5993654.html只需一行命 ...

  3. 吴裕雄--天生自然python学习笔记:Python CGI编程

    什么是CGI CGI 目前由NCSA维护,NCSA定义CGI如下: CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户 ...

  4. 吴裕雄--python编程:CGI编程

    什么是CGI CGI 目前由NCSA维护,NCSA定义CGI如下: CGI(Common Gateway Interface),通用网关接口,它是一段程序,运行在服务器上如:HTTP服务器,提供同客户 ...

  5. python CGI 编程实践

    文章更新于:2020-03-05 注1:安装 python 参见: python 的安装使用和基本语法 注2:配置 web 环境参见: Windows&linux使用集成环境搭建 web 服务 ...

  6. 《Python 数据库 GUI CGI编程》

    本文地址:http://www.cnblogs.com/aiweixiao/p/8390417.html 原文地址 点击关注微信公众号 wenyuqinghuai 1.写在前边 上一次,我们介绍了Py ...

  7. python3高级编程

    1. SMTP发送邮件 internet相关协议: http:网页访问相关,httplib,urllib,xmlrpclib ftp:文件传输相关, ftplib, urllib nntp:新闻和帖子 ...

  8. Perl CGI编程

    http://www.runoob.com/perl/perl-cgi-programming.html 什么是CGI CGI 目前由NCSA维护,NCSA定义CGI如下: CGI(Common Ga ...

  9. CGI编程学习

    @CGI编程学习 目录(?)[+] 一.基本原理 CGI:通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口.通过CGI接口,Web服务器就能 ...

随机推荐

  1. 内部类不能有静态变量(除静态的对Static的理解)

    关于内部类(static与final) Static 不用实例化就能加载进内存 而内部类需要外部类实例化后才能加载进内存.这就间接造成static需要实例化了.与static不需要实例化语义矛盾 1. ...

  2. 解决ionic安装不上的方法

    (1)打开nodeJs按正常步骤来install -g -d ionic ,等待执行完毕  (2) 不管成不成功,打开C:\Users\keranbing\AppData\Roaming\npm\no ...

  3. logger(二)logback简介及其实现原理

    一.logback简介 logback是log4j创始人写的,性能比log4j要好,目前主要分为3个模块 logback-core:核心代码模块 logback-classic:log4j的一个改良版 ...

  4. Python基础(二)--基本数据类型、格式化输出、基本运算符

    一.基本数据类型 1.数字类型 #int整型 定义:age=10 #age=int(10) 用于标识:年龄,等级,身份证号,qq号,个数 #float浮点型 定义:salary=3.1 #salary ...

  5. Qemu-4.1 桥接网络设置

    参考: [qemu] qemu旧的net参数已经不再可用了,新的这样用. QEMU's new -nic command line option 用Qemu模拟vexpress-a9 --- 配置 q ...

  6. python数据类型之三

    字典 字典的基本结构 # 字典, 键值对 dict类# 字典的基本结构# 字典的值可以是任何值# 字典的键不能是列表,字典, 最好也不要用布尔值(可能会和1和0重复)# 字典无序, my_dict = ...

  7. dapi 基于Django的轻量级测试平台七 怎样部署到生产环境

    QQ群: GitHub:https://github.com/yjlch1016/dapi Nginx+uWSGI 前置条件:以下所有操作均在root账号下面进行如果不是root用户请注意权限问题因为 ...

  8. 使用WIFI准备工作及配置内核——韦东山

    主要做的工作:让内核如何支持现有的无线网卡.知道这个流程就可以了,没必要深究. 使用WIFI功能时,涉及两个东西: 同样手机也可以用于WIFI AP模式,让别的设备来连接它.就是我们平时所说的用手机开 ...

  9. destoon聚合搜索页面模板

    最近学习大型站点SEO策略,谈到关于大站需要做聚合页面tags,所以根据destoon系统自己做了一个聚合页面,在此分享给吾爱的朋友,一起学习参考! 模板演示站点:http://zhimo.yuanz ...

  10. P1908 逆序对-(cdq分治)

    https://www.luogu.org/problem/P1908 沿用归并排序的思想求逆序对. 坑1:结果爆int型,需要用longlong 坑2:相对于归并排序,在比较的时候多了一个等号 举例 ...