前言:CGI虽然已经过时,但对于一些功能少的网页还是有意义的,很方便,不必学习其他语言徒增时间成本。
作者花了两天时间(1天技术储备,1天实际动手写),用apache2+Ubuntu+ptyhon3 CGI,写了个功能简单的小网页,改了html网页模板发送post请求,用.py接收并执行用户post请求(挂在境外服务器给别人申请shadowsocks端口号玩,因为功能不多,就直接用.py了)。实践过程中遇到了一些坑,作者小白,对于很多问题无法寻根溯源、融会贯通,网上的直接资料很少,故记录一下问题和解决方式。
注明:下面提到的CGI文件都指的是通过CGI执行的python文件
1.配置apache2 CGI过程 .conf文件问题
网上很多教程都比较老,涉及httpd.conf配置文件,而当前的Ubuntu下apache2配置文件已经分成了若干个.conf的组合,我按https://blog.youkuaiyun.com/u011728480/article/details/51871298才配置成功。
2.CGI文件权限问题
环境配置好了访问页面下的./cgi-bin/*.py不会提示404,而是提示无权限,需要使用
chmod 755 *.py
给权限。755权限解释如下:
1.文件所有者可读可写可执行 --7
2.与文件所有者同属一个用户组的其他用户可读可执行 --5
3.其它用户组可读可执行 --5
当然,大多数教程都提到了cgi文件的权限,不容易遇到这个坑。
3.python3的cgi文件在网页上无输出
一般来说,当python CGI文件本身执行有错误时,访问./cgi-bin/*.py会直接提示错误。但我在实践过程(linux)中,发现CGI文件中print(‘中文’)是没有顺利执行的(程序来这里停止了),为什么没报错我现在也不清楚。。。代码前的#coding:uft-8
编码声明似乎没有生效。在某个论坛中找到一个声明方式:
import codecs, sys
sys.stdout = codecs.getwriter('utf8')(sys.stdout.buffer)
才成功。这里我要吐槽一下菜鸟教程python CGI,在CGI教程的最后才通过一篇笔记提到这个问题。。你这篇教程这么长,我前面都没调通怎么可能往后面的get/post请求看啊。。。当然其他的还是很感激菜鸟教程的
4.关于CGI文件读html文件显示的问题
有时候我们并不想整个页面都print(),而是想直接读.html文件(有中文),然后print()。在linux环境下,显示老是有问题(当然这还涉及到css,imanges等路径的问题,下面提到)。。
事实上,这里还需要对读入进行转码,请参考以下代码:
import codecs, sys
print("Content-type:text/html\r\n\r\n")# 空行,告诉服务器结束头部
f=codecs.open('../html/index.html',encoding='UTF-8')
s=f.read()
f.close()
print(s)
5.关于路径的问题
首先,本地/cgi-bin/内的.html文件是不可以直接通过浏览器访问的,似乎是因为该文件夹内只能执行CGI文件。
假设apache2根目录为/var/www/html
, 无论你的/cgi-bin/实际在服务器何处,浏览器访问/cgi-bin/*.py都认为当前路径是在./html/cgi-bin/
中,如你执行的CGI文件的html代码要访问/var/www/html/css/1.css
,html中路径应写为../css/1.css
。。。
PS:感觉这个大家都不会遇到这个问题,作者当时脑抽了,还想了一下,主要是对web服务器不太了解。。
6.关于CGI文件操作本地文件
我在服务器/cgi-bin/本地执行python3 *.py
时(涉及读写服务器本地文件),程序并没有问题,但通过浏览器访问执行CGI时,都会报错,然后通过资料发现又是权限问题(欸?我为什么要说又。。),将要操作的本地文件权限变成666(是的,就是six six six)
chmod 666 filename
666权限表述为
chmod 666 means that all users can read and write but cannot execute
也就是所有用户都可以读写,但不能执行该文件。(777为所有用户,所有操作)
顺便提一下:
使用套接字AF_UNIX协议族时,其实是在操作一个本地的文件,当CGI文件需要用到这种套接字绑定本地接口文件时,需要对该文件进行666改权限操作,如:
socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
cli.bind('/tmp/client.sock') # address of the client
cli.connect('/var/run/shadowsocks-manager.sock') # address of Shadowsocks manager
首先要
chmod 666 /var/run/shadowsocks-manager.sock