Python的Web编制程序[一] -> Web服务器[0] -> Web 服务器与 CGI / WSGI

在类型支付进度中,大家壹般搭建局域网进行项目开发,并展开内部测试,发现bug举办校对,最后会把1段时代的支付成果(文件)上流传公网服务器实行体现,一般壹段时间更新1回。比如我们以此种类,16日更新一回到四次,那里结合本身的实操写一下项目由中间局域网服务器更新到公网服务器的步子。总体的规则是有限辅助数据的平安,保留原有数据,如果更新战败能够恢复生机原有的顺序数据。

Web服务器 / Web
Server

一、项目文件的立异


一 打包局域网(开发)服务器数据

 

用ssh登录到服务器,cd到支付文件的目录,使用tar将索要备份的文本夹(文件)进行打包,比如供给打包abc目录

对于Web来说,供给树立一个Web服务器,必须树立3个核心的服务器和一个处理程序

tar –cvf devbak20170217.tar abc/

宗旨服务器的主要效率是,在客户端和服务器端达成须要的HTTP交互,

这么就把abc目录打包成了devbak20170217.tar文件。

处理程序的机要功用是,处理客户端的呼吁,并回到适当的文本,包蕴静态/动态文件。

二 备份公网服务器数据

1 树立服务器
/ Setup Server

操作步骤与打包局域网服务器数据类似,将备份的打包文件命名字为pubbak20170二壹7.tar。

在Python中,有多个平放http包,包括了server和client模块,当中server模块包涵了几个类,分别为宗旨服务器类HTTPServer(基类为socketserver.TCPServer),和多少个处理程序类,BaseHTTPRequestHandler类(基类为socketserver.StreamRequestHandler),SimpleHTTP-RequestHandler类(基类为BaseHTTPRequestHandler)以及CGIHTTPRequestHandler类(基类为SimpleHTTPRequestHandler),以及三个常用的test函数。

三 更新公网服务器数据

Note:
在Python3事先,这八个类在四个单身模块中,分别为BaseHTTPServer(包括HTTPServer类),SimpleHTTPServer,CGIHTTPServer。对于着力处理程序的类来说,能够通过重定义以下多少个措施:
do_GET/do_POST/do_HEAD等来落到实处相应处理作用。

公网服务区数据现已打包备份,那时能够先将原目录更换名字,比如abc目录,使用

1.1
主导服务器

mv abc abc_bak

行使http.server提供的HTTPServer和BaseHTTPRequestHandler几个类建立1个不难易行的服务器及处理程序。

命令将abc目录更换名称,方便更新出错后的回复。然后将开发服务器的打包数据拷贝进来,然后解包。

全体代码

tar –xvf devbak20170217.tar

起名 1起名 2

如此就把开发服务器的abc目录解压到了当前目录,然后利用浏览器举办测试,看是否达到规定的标准预期目标,假诺达到了预想的结果,更新职责成功,测试如若没不平时,就能够把abc_bak那么些目录删掉,一时半刻保留pubbak20170二一七.tar那一个备份的打包文件。

 1 from http.server import BaseHTTPRequestHandler, HTTPServer
 2 
 3 # http://localhost:80/first_html.html to GET file
 4 class MyHandler(BaseHTTPRequestHandler):
 5     def do_GET(self):
 6         try:
 7             f = open(self.path[1:], 'r')
 8             self.send_response(200)
 9             self.send_header('Content-type', 'text/html'.encode())
10             self.end_headers()
11             self.wfile.write(f.read().encode())
12             f.close()
13         except IOError:
14             self.send_error(404,
15                     'File NOt Found: %s' % self.path)
16 
17 def main():
18     try:
19         server = HTTPServer(('', 80), MyHandler)
20         print('Welcome to the machine... Press ^C once or twice to quit.')
21         server.serve_forever()
22     except:
23         print('^C received, shutting down server')
24         server.socket.close()
25 
26 if __name__ == '__main__':
27     main()

二、数据库的换代

View Code

服务器的前台展现供给调用后台的数目,也正是数据库的数目,我们在开发进度中,也有望会更新数据库。在支付进度中尽量保险开发服务器的数据库和公网服务器的数据库1致,那样每一次变更都极小。在立异公网数据库以前大家也是要做好备份,大家项目利用的数据库是mysql,项目中动用navicat对数据库进行操作,相比便于。比如,大家前些天内需把开发服务器的数据库更新到公网服务器。可按下边包车型地铁操作举行。

分段解释

一 备份公网数据库

率初始入所需的模块,通过接二连三基本处理程序类,并重载do_GET方法来落实对GET的拍卖。个中send_response()发送http状态码,send_header()发送http头部新闻,end_headers()添加尾部甘休表示符,通过wfile的write函数将点名路线读取的始末传给用户。

在对数据库直接增加和删除改从前,一定要先备份数据库。使用navicat先连接数据库,双击供给操作的数据库,在数据库名上点击右键,选取“转储SQL文件…”,会唤起您存款和储蓄数据库,比如大家起名称为abc.sql,把那个备份文件存储到合适的地点。

 1 from http.server import BaseHTTPRequestHandler, HTTPServer
 2 
 3 # http://localhost:80/first_html.html to GET file
 4 class MyHandler(BaseHTTPRequestHandler):
 5     def do_GET(self):
 6         try:
 7             f = open(self.path[1:], 'r')
 8             self.send_response(200)
 9             self.send_header('Content-type', 'text/html'.encode())
10             self.end_headers()
11             self.wfile.write(f.read().encode())
12             f.close()
13         except IOError:
14             self.send_error(404,
15                     'File NOt Found: %s' % self.path)

贰 备份开发数据库

概念一个主函数用于运营服务器,在那之中ip为localhost,端口为80,传入自定义的处理程序。运转服务器后,可以应用Web客户端(各样浏览器),输入相应的url(确定保证GET的公文与url钦赐的文件相称),如http://localhost:80/first\_html.html来获得网页文件音信。

操作步骤,和备份公网服务器数据库类似。

 1 def main():
 2     try:
 3         server = HTTPServer(('', 80), MyHandler)
 4         print('Welcome to the machine... Press ^C once or twice to quit.')
 5         server.serve_forever()
 6     except:
 7         print('^C received, shutting down server')
 8         server.socket.close()
 9 
10 if __name__ == '__main__':
11     main()

三 更新公网数据库表

透过地点的粗略示例可以对服务器实行进一步的扩大,从而达成越多的成效。

借使每趟变更相当小的话,而且我们对转移的数据库表很纯熟,可以只对须要修改的表展开翻新,而不是立异任何数据库,那样改动的数量比较少,绝对安全一些。然则供给注意的是表之间是还是不是存在涉嫌关系,直接更新数据库表一定要熟稔数据库才行。

1.2
CGI服务器

具体操作步骤,也是用navicat,在支付服务器上开辟须要更新的多少库表,右键点击,选拔“转储SQL文件”,在适龄的岗位保存这些表文件,比如起名t_edf.sql。在公网服务器数据库下有“表”,在“表”上点击右键,采纳“运维SQL文件…”,在开拓的公文夹中甄选刚刚存款和储蓄的SQL文件,打开,那样就更新了四个数据库的表,假设有多少个表须求创新,则重复操作。

接下去介绍利用http.server中的CGIHTTPRequestHandler协作HTTPServer来建立贰个CGI服务器,

四 更新公网数据库

1 # e.g.:
2 # Connect following link to GET HTML
3 # http://localhost:8000/static_screen.html
4 from http.server import CGIHTTPRequestHandler, test
5 test(CGIHTTPRequestHandler)

比方数据库改动相比较多,大概大家对数据库的表间关系不是特意领悟,能够应用更新任何数据库的诀窍,前提是毫无疑问要搞好备份。前提是毫无疑问要盘活备份。前提是自可是然要盘活备份。主要的作业说三回,倘若未有备份,数据库爆发难题会很忙绿。那么些立异也相比较不难,直接在公网服务器上开辟数据库,然后在数据库上点击右键,选用刚刚保存的付出服务器的sql文件(abc.sql),打开,等待数据更新,更新实现后关闭。

应用http的CGI服务器的创立十三分简短,只需求导入处理模块和test函数,再运维即可。

③ 别的需求小心的难点

Note:
此处值得注意的有以下两点,

品种文件包蕴前台体现的公文、后台管理的文件、后端开发的文书、财富文件(图片、录制、文件等),如果将富有文件都更新,恐怕花的时光相比较长,那时能够选取改变的文书,别的文件不立异,原则是要把改变的文本全体翻新。比如那段时光只开发了前台展示的文件,更新的时候就足以不立异后台管理文件和后端开发文件,能源文件壹般也要翻新,依据具体意况选取。

  1. 在CGIHTTPRequestHandler中,设置了暗许的cgi目录为/cgi-bin(以及/htbin),由此须求在本子所在目录下建立相应的cgi-bin文件夹,并存放相应cgi文件,这样才会运行cgi脚本,不然只会作为平日的文本文件返回;
  2. test函数中,私下认可使用HTTPServer作为主导服务器,使用localhost以及端口八千当做三番五次参数,协议为HTTP/一.0,处理程序默许为BaseHTTPRequest-Handler。

万1服务器使用的是tomcat服务器,在立异后端开发文件从此,需求重启tomcat才行。尽管更新任何文件,不用重启tomcat。

 

如上操作是在品种中用到的,然则项目还一向不上线运维,也正是公网服务器数据库数据更新不是许多,假如运转来说,或然还要选择翻新时间,在人少的时候,暂且关张服务,而且尽量在十分的短的小时内更新维护数据,运维之后更新大概还会赶上很多新的题材,也应该有更加好的化解办法,那亟需在之后的做事持续计算,希望我们多提宝贵意见。

2
通用网关接口CGI / Common Gateway Interface

2.1 CGI简介

Common Gateway
Interface(CGI)是1种概念的标准接口,用于在外表应用程序(CGI程序)和Web服务器时期的音讯传递,CGI的专业允许Web服务器执行外部程序,并将那几个外部程序的输出发送给Web浏览器。其首要办事流程如下,

  1. 浏览器通过HTML表单超链接恳请指向3个CGI应用程序URL;
  2. 服务器收到请求;
  3. 服务器执行钦点CGI应用程序;
  4. CGI应用程序执行所急需的操作,日常是基于浏览者输入的始末;
  5. CGI应用程序把结果格式化为网络服务器和浏览器能够精通的文书档案(日常是HTML网页);
  6. 网络服务器把结果重临到浏览器中。

值得注意的是,CGI应用程序时运维在服务器系统上的,执行时会消耗服务器的CPU和内部存款和储蓄器。同时不健全的CGI应用程序还有望变为违法进入服务器的坦途。近日,1般的生育条件都已不复利用CGI。

2.2
启动CGI服务器

先是,需求打开CGI的服务器,能够挑选直接运维前边的CGI服务器脚本或在指令行中通过下列命令直接开发银行服务器,

python -c "from http.server import CGIHTTPRequestHandler, test;test(CGIHTTPRequestHandler)" 

二.3
CGI应用程序

接下去介绍在服务器运营的前提下,使用CGI程序完结客户端与服务器之间的交互成效。

2.3.1
静态表单与CGI结果页面

动用静态的html页面来扭转表单,同时在html中定义按钮触发cgi程序运维,生成重返的结果表单。

切实成效如下,

在浏览器中输入url:
http://localhost:8000/static_screen.html,将会议及展览示基本页面如下,

起名 3

透过填好名字后单击submit按钮获得再次回到页面如下,

起名 4

回来页面包车型客车url为,http://localhost:8000/cgi-bin/cgi_sleep.py?person=LIKE&howmany=7,通过该url能够看来,cgi应用程序的职位,以及呼吁表单提供的音讯(person=LIKE,howmany=柒)。

兑现上述功能,首先需求定义静态的表单页面,首先定义底部标题,随后展现h3,定义表单的action指向cgi-bin中的cgi应用程序,更创制多少个表单(radio类型)输入以及1个交付按钮(submit类型),html代码如下,

 1 <html>
 2     <head>
 3         <title>
 4             Sleep(Static Screen CGI demo)
 5         </title>
 6     </head>
 7     <body>
 8         <h3>
 9             Sleep list for: <i>NEW USER</i>
10         </h3>
11         <form action="/cgi-bin/cgi_sleep.py">
12             <b>Enter your Name:</b>
13             <input type=text name=person value="NEW USER" size=15>
14             <p>
15                 <b>How many hours you sleep a day?</b>
16                 <input type=radio name=howmany value='5' checked> 5h
17                 <input type=radio name=howmany value='6'> 6h
18                 <input type=radio name=howmany value='7'> 7h
19                 <input type=radio name=howmany value='8'> 8h
20                 <input type=radio name=howmany value='9'> 9h
21             <p><input type=submit> <--Click
22         </form>
23     </body>
24 </html>

概念好表单之后,还要求定义表单中针对的cgi程序,

代码如下

import cgi

reshtml = '''Content-Type: text/html\n
<html><head><title>
Sleep(Dynamic Screen CGI demo)
</title></head>
<body><h3>sleep list for: <i>%s</i></h3>
Your name is: <b>%s</b><p>
You sleep <b>%s</b> hours a day.
</body></html>'''

# cgi.FieldStorage will catch the form from web client
form = cgi.FieldStorage()

# Get the value
who = form['person'].value
howmany = form['howmany'].value

# print should be html format, and will be return back to web client
print(reshtml % (who, who, howmany))

首起首入cgi模块,同时定义重临的html页面,在那之中包蕴再次回到的头顶类型,text/html

cgi模块的FiledStorage类达成了CGI的数额交互效能,首先对其实行实例化,获得的实例中隐含client提交的表单新闻内容,能够直接通过键值取值获取,而cgi应用程序最后输出(print)的结果将会被重回给客户端。

 

贰.叁.2
CGI表单和结果页面

2.3.2.1
着力版本

除此之外静态表单外,仍是能够利用CGI程序动态变化表单和尾声的结果页面,将下边包车型大巴cgi程序放在cgi-bin目录下,通过浏览器的url指向该脚本,由于CGIServer中开始展览了判断会对py(以及pyc)文件进行运作,因而能够直接调用cgi程序。不然将回来文本音信。

总体代码

起名 5起名 6

 1 """
 2 Run Server first
 3 Connect address: Http://localhost:8000/cgi-bin/cgi_combined_primary.py
 4 """
 5 import cgi
 6 
 7 # Http header
 8 header = 'Content-Type: text/html\n\n'
 9 
10 # Html form
11 formhtml = '''<html><head><title>
12 Sleep CGI Demo</title></head>
13 <body><h3>Sleep list for: <i>NEW USER</i></h3>
14 <form action='/cgi-bin/cgi_combined_primary.py'>
15 <b>Enter your Name: </b>
16 <input type=hidden name=action value=edit>
17 <input type=text name=person value='NEW USER' SIZE=15>
18 <p><b>How many hours you sleep a day?</b>
19 %s
20 <p><input type=submit></form></body></html>'''
21 
22 fradio = '<input type=radio name=howmany value="%s" %s> %s\n'
23 
24 def showForm():
25     sleep = []
26     for i in range(5, 10):
27         checked = ''
28         if i == 5:
29             checked = 'CHECKED'
30         sleep.append(fradio % (str(i), checked, str(i)))
31     print('%s%s' % (header, formhtml % ''.join(sleep)))
32 
33 reshtml = '''<html><head><title>
34 Sleep CGI Demo</title></head>
35 <body><h3>Sleep list for: <i>%s</i></h3>
36 Your name is: <b>%s</b><p>
37 You sleep <b>%s</b> hours a day.
38 </body></html>'''
39 
40 def doResults(who, howmany):
41     print(header + reshtml % (who, who, howmany))
42 
43 def process():
44     form = cgi.FieldStorage()
45     if 'person' in form:
46         who = form['person'].value  # resp
47     else:
48         who = 'NEW USER'    # show
49 
50     if 'howmany' in form:
51         howmany = form['howmany'].value # resp
52 
53     else:
54         howmany = 0     # show
55 
56     # Use action label to judge show or response
57     if 'action' in form:
58         doResults(who, howmany) # resp
59     else:
60         showForm()  # show
61 
62 if __name__ == '__main__':
63     process()

View Code

最后页面的显示结果如下

起名 7

 

 

输入用户名点击提交后显得如下界面,

起名 8

支行解释

导入模块后,定义http的尾部,以及表单页面包车型地铁html代码,个中须要专注的是,壹五行中的三个表单类型为hidden,即为不可知的,并且起名字为action,值为edit,其意在作为二个判定标志,用于判断是二个新交付表单还是1个回来结果的表单,从而执行相应的函数进行处理。

 1 """
 2 Run Server first
 3 Connect address: Http://localhost:8000/cgi-bin/cgi_combined_primary.py
 4 """
 5 import cgi
 6 
 7 # Http header
 8 header = 'Content-Type: text/html\n\n'
 9 
10 # Html form
11 formhtml = '''<html><head><title>
12 Sleep CGI Demo</title></head>
13 <body><h3>Sleep list for: <i>NEW USER</i></h3>
14 <form action='/cgi-bin/cgi_combined_primary.py'>
15 <b>Enter your Name: </b>
16 <input type=hidden name=action value=edit>
17 <input type=text name=person value='NEW USER' SIZE=15>
18 <p><b>How many hours you sleep a day?</b>
19 %s
20 <p><input type=submit></form></body></html>'''
21 
22 fradio = '<input type=radio name=howmany value="%s" %s> %s\n'

showForm()函数用于添加表单输入框,

1 def showForm():
2     sleep = []
3     for i in range(5, 10):
4         checked = ''
5         if i == 5:
6             checked = 'CHECKED'
7         sleep.append(fradio % (str(i), checked, str(i)))
8     print('%s%s' % (header, formhtml % ''.join(sleep)))

随即定义重返的html,以及再次回到处理函数,用于将回来的结果添加到再次回到html中。

1 reshtml = '''<html><head><title>
2 Sleep CGI Demo</title></head>
3 <body><h3>Sleep list for: <i>%s</i></h3>
4 Your name is: <b>%s</b><p>
5 You sleep <b>%s</b> hours a day.
6 </body></html>'''
7 
8 def doResults(who, howmany):
9     print(header + reshtml % (who, who, howmany))

末尾定义进度函数,首先实例化cgi生成表单实例,此时,判断表单中是或不是有person和howmany项,若有则印证是提交的表单页,则收获表单新闻,未有则表达是第①提供的表单页,设置暗许值。接着利用action标志判断是哪壹种表单,执行相应处理程序。此处也得以借助person和howmany字段来判定,但运用action字段更清晰明了。

 1 def process():
 2     form = cgi.FieldStorage()
 3     if 'person' in form:
 4         who = form['person'].value  # resp
 5     else:
 6         who = 'NEW USER'    # show
 7 
 8     if 'howmany' in form:
 9         howmany = form['howmany'].value # resp
10 
11     else:
12         howmany = 0     # show
13 
14     # Use action label to judge show or response
15     if 'action' in form:
16         doResults(who, howmany) # resp
17     else:
18         showForm()  # show
19 
20 if __name__ == '__main__':
21     process()

 

2.3.2.2
晋级版本

对上边生成表单和结果页面包车型大巴CGI程序开展升级,添加或改变了以下多少个功能,

  1. 不安装暗中同意勾选选项,当未采用选项时,再次来到报错页面提示错误;
  2. 设置再次回到锚,输入消息后单击重临锚会重返原页面,并自行填写以前输入的新闻。

总体代码

起名 9起名 10

 1 """
 2 Run Server first
 3 Connect address: Http://localhost:8000/cgi-bin/cgi_combined_advanced.py
 4 """
 5 import cgi
 6 from urllib.parse import quote_plus
 7 
 8 # Http header
 9 header = 'Content-Type: text/html\n\n'
10 url = '/cgi-bin/cgi_combined_advanced.py'
11 
12 errhtml = '''<html><head><title>
13 Sleep CGI Demo</title></head>
14 <body><h3>ERROR</h3>
15 <b>%s</b><p>
16 <form><input Type=button value=Back onclick="window.history.back()"</form>
17 </body></html>'''
18 
19 def showError(error_str):
20     print(header + errhtml % error_str)
21 
22 formhtml = '''<html><head><title>
23 Sleep CGI Demo</title></head>
24 <body><h3>Sleep list for: <i>%s</i></h3>
25 <form action="%s">
26 <b>Enter your Name: </b>
27 <input type=hidden name=action value=edit>
28 <input type=text name=person value="%s" SIZE=15>
29 <p><b>How many hours you sleep a day?</b>
30 %s
31 <p><input type=submit></form></body></html>'''
32 
33 fradio = '<input type=radio name=howmany value="%s" %s> %s\n'
34 
35 def showForm(who, howmany):
36     sleep = []
37     for i in range(5, 10):
38         checked = ''
39         if str(i) == howmany:
40             checked = 'CHECKED'
41         sleep.append(fradio % (str(i), checked, str(i)))
42     print('%s%s' % (header, formhtml % (who, url, who, ''.join(sleep))))
43 
44 reshtml = '''<html><head><title>
45 Sleep CGI Demo</title></head>
46 <body><h3>Sleep list for: <i>%s</i></h3>
47 Your name is: <b>%s</b><p>
48 You sleep <b>%s</b> hours a day.
49 <p>Click <a href="%s">here</a> to edit your data again.
50 </body></html>'''
51 
52 def doResults(who, howmany):
53     newurl = url + '?action=reedit&person=%s&howmany=%s' % (quote_plus(who), howmany)
54     print(header + reshtml % (who, who, howmany, newurl))
55 
56 def process():
57     error = ''
58     form = cgi.FieldStorage()
59 
60     if 'person' in form:
61         who = form['person'].value.title()  # Resp
62     else:
63         who = 'NEW USER'    # Show
64 
65     if 'howmany' in form:
66         howmany = form['howmany'].value # Resp
67     else:
68         if 'action' in form and form['action'].value == 'edit':
69             error = 'Please select hours of sleep.' # Error
70         else:
71             howmany = 0     # Show
72 
73     if not error:
74         if 'action' in form and form['action'].value != 'reedit':
75             doResults(who, howmany) # Resp
76         else:
77             showForm(who, howmany)  # Show
78     else:
79         showError(error)    # Error
80 
81 if __name__ == '__main__':
82     process()

View Code

运转服务器并输入钦定的U揽胜极光L后,可以见见如下页面,与主干版本的页面周边,但是并未有勾选暗许选项。

起名 11

若此时不接纳任何选择,直接单击提交按钮,则CGI程序会回来如下的错误提醒页面,此时单击重回按钮则会回到从前的页面。

起名 12

再次来到从前页面填入名字勾选选项后,会显示结果页面如下,此时得以经过点击here锚链接回到以前选拔的页面。

起名 13

分层解释

先是导入模块,定义通用的http底部以及url的path音信,

 1 """
 2 Run Server first
 3 Connect address: Http://localhost:8000/cgi-bin/cgi_combined_advanced.py
 4 """
 5 import cgi
 6 from urllib.parse import quote_plus
 7 
 8 # Http header
 9 header = 'Content-Type: text/html\n\n'
10 url = '/cgi-bin/cgi_combined_advanced.py'

概念错误提示页面包车型客车html,设置3个表单后退按钮(JavaScript),单击后回到前页面,由于按钮是输入型,因而须要一个表单。

再定义展现错误函数,再次来到html尾部以及错误提醒页面html以及错误音讯。

1 errhtml = '''<html><head><title>
2 Sleep CGI Demo</title></head>
3 <body><h3>ERROR</h3>
4 <b>%s</b><p>
5 <form><input Type=button value=Back onclick="window.history.back()"</form>
6 </body></html>'''
7 
8 def showError(error_str):
9     print(header + errhtml % error_str)

随着定义显示页面,以及呈现函数,与前边基本版本的好像。

 1 formhtml = '''<html><head><title>
 2 Sleep CGI Demo</title></head>
 3 <body><h3>Sleep list for: <i>%s</i></h3>
 4 <form action="%s">
 5 <b>Enter your Name: </b>
 6 <input type=hidden name=action value=edit>
 7 <input type=text name=person value="%s" SIZE=15>
 8 <p><b>How many hours you sleep a day?</b>
 9 %s
10 <p><input type=submit></form></body></html>'''
11 
12 fradio = '<input type=radio name=howmany value="%s" %s> %s\n'
13 
14 def showForm(who, howmany):
15     sleep = []
16     for i in range(5, 10):
17         checked = ''
18         if str(i) == howmany:
19             checked = 'CHECKED'
20         sleep.append(fradio % (str(i), checked, str(i)))
21     print('%s%s' % (header, formhtml % (who, url, who, ''.join(sleep))))

再定义结果回到页面,此处2个鲜明的区分在于多了二个锚,以here展现,链接锚指向新的url(在原url中连着了新的表单提交新闻,设置action为reedit,person和howmany为事先表单提交值)。

 1 reshtml = '''<html><head><title>
 2 Sleep CGI Demo</title></head>
 3 <body><h3>Sleep list for: <i>%s</i></h3>
 4 Your name is: <b>%s</b><p>
 5 You sleep <b>%s</b> hours a day.
 6 <p>Click <a href="%s">here</a> to edit your data again.
 7 </body></html>'''
 8 
 9 def doResults(who, howmany):
10     newurl = url + '?action=reedit&person=%s&howmany=%s' % (quote_plus(who), howmany)
11     print(header + reshtml % (who, who, howmany, newurl))

聊到底定义进度函数,首先是error消息为空,实例化表单类,对表单实例举办判断,要是person是回到表单,则将表单人名大写,再判断howmany字段,当存在时,表明是回来结果表单,若不设有,判断action是新表单仍旧不对表单。最后根据error和action字段实行实践相应函数。

 1 def process():
 2     error = ''
 3     form = cgi.FieldStorage()
 4 
 5     if 'person' in form:
 6         who = form['person'].value.title()  # Resp
 7     else:
 8         who = 'NEW USER'    # Show
 9 
10     if 'howmany' in form:
11         howmany = form['howmany'].value # Resp
12     else:
13         if 'action' in form and form['action'].value == 'edit':
14             error = 'Please select hours of sleep.' # Error
15         else:
16             howmany = 0     # Show
17 
18     if not error:
19         if 'action' in form and form['action'].value != 'reedit':
20             doResults(who, howmany) # Resp
21         else:
22             showForm(who, howmany)  # Show
23     else:
24         showError(error)    # Error
25 
26 if __name__ == '__main__':
27     process()

 

2.3.3
进阶作用CGI

动用CGI程序达成3个带有以下几个特点的服务器交互功用,包罗,

  1. Cookie的使用;
  2. 同3个CGI字段的多少个值;
  3. 行使multipart表单提交格局贯彻公文上传。

multipart

当前CGI中特意提议只同意存在二种表单编码,分别为“application/x-www-form-urlencoded”“multipart/form-data”三种,在交付2个表单时,能够对表单的编码格局encode-type实行宣示,暗中认可编码格局为第1种,由此下边包车型客车扬言是能够差不多的,

<form enctype="application/x-www-form-urlencoded" ...>  

而当供给采纳multipart表单时,则需求评释multipart编码情势,证明格局如下,

<form enctype=" multipart/form-data" ...>  

起名,在交付表单时得以应用上述的四意壹种,而上传文件时只可以动用multipart编码情势,接着通过输入文件类型完结文件上传,

<input type=file name=...>  

那段指令能够展示叁个空的文本框,同时旁边有个按钮,能够经过按钮浏览文件找到上传文件。

多值字段

多值字段的常见情状为有1多级的复选框允许用户展开多选,每一种复选框都有壹致的字段名,但为了区别那些复选框,会选拔分歧的值与一定的复选框关联。

当复选框多选时,2个键将会对应多个值,在那种地方下cgi模块会树立一个包蕴这一个类实例的列表,能够透过遍历获取具有的值。

Cookie

由于HTTP是一个无状态音信的商议,因而为了维持在多少个页面之间浏览的三番五次性,则供给使用cookie,服务器会向客户端发送3个呼吁来保存cookie,从而让用户的音讯数据等保存在客户端处,而不须要占用服务器存款和储蓄或行使服务器页面嵌入数据的办法来保持数据。

 

在客户端获得请求文件在此以前,Web服务器会向客户端发送“Set-Cookie”头文件来必要客户端存款和储蓄cookie。1旦客户端建立起了cookie,HTTP_主任KIE环境变量会将那么些cookie自动放到请求中发送给服务器。cookie是以支行分隔键值对留存的,即以分行‘;’分隔种种键值对,每一种键值对中级都由等号‘=’分开。为此需求展开手动拆分解析。

功能达成

为落成上述多少个职能,必要叁个稍稍复杂一点的CGI程序,具体代码如下,

1体化代码

 

起名 14起名 15

  1 from cgi import FieldStorage
  2 from os import environ
  3 from io import StringIO
  4 from urllib.parse import quote, unquote
  5 
  6 class AdvCGI(object):
  7     header = 'Content-Type: text/html\n\n'
  8     url = '/cgi-bin/cgi_advanced.py'
  9 
 10     formhtml = '''<html><head><title>
 11 Advanced CGI Demo</title></head>
 12 <body><h2>Advanced CGI Demo Form</h2>
 13 <form method=post action="%s" enctype="multipart/form-data">
 14 <h3>My Cookie Setting</h3>
 15 <li><code><b>CPPuser = %s</b></code>
 16 <h3>Enter cookie value<br>
 17 <input name=cookie value="%s"> (<i>optional</i>)</h3>
 18 <h3>Enter your name<br>
 19 <input name=person value="%s"> (<i>required</i>)</h3>
 20 <h3>What languages can you program in?
 21 (<i>at least one required<i>)</h3>
 22 %s
 23 <h3>Enter file to upload <small>(max size 4K)</small></h3>
 24 <input type=file name=upfile value="%s" size=45>
 25 <p><input type=submit>
 26 </form></body></html>'''
 27 
 28     langSet = ('Python', 'Ruby', 'Java', 'C++', 'PHP', 'C', 'JavaScript')
 29     # Set checkbox for language items,
 30     # First %s for real value, second one for CHECKED or not, third one for presented value
 31     langItem = '<input type=checkbox name=lang value="%s"%s> %s\n'
 32 
 33     # Read cookies from client
 34     def getCPPCookies(self):
 35         # environ contains the environment info, similar to dict usage
 36         # Check whether cookie exists
 37         if 'HTTP_COOKIE' in environ:
 38             # environ['HTTP_COOKIE'] could be like: 'CPPinfo=Like%3APython%2CJava%3AC%3A\path...; CPPuser=Self'
 39             # %3A -> :
 40             # %2C -> ,
 41             cookies = [x.strip() for x in environ['HTTP_COOKIE'].split(';')]
 42             # cookies = ['CPPinfo=Like%3APython%2CJava%3AC%3A\path...', 'CPPuser=Self']
 43             for eachCookie in cookies:
 44                 if len(eachCookie) > 6 and eachCookie[:3]=='CPP':
 45                     # tag -> info / user
 46                     tag = eachCookie[3:7]
 47                     try:
 48                         self.cookies[tag] = eval(unquote(eachCookie[8:]))
 49                     except (NameError, SyntaxError):
 50                         self.cookies[tag] = unquote(eachCookie[8:])
 51             if 'info' not in self.cookies:
 52                 self.cookies['info'] = ''
 53             if 'user' not in self.cookies:
 54                 self.cookies['user'] = ''
 55         else:
 56             self.cookies['info'] = self.cookies['user'] = ''
 57 
 58         if self.cookies['info'] != '':
 59             print(self.cookies['info'])
 60             try:
 61                 self.who, langStr, self.fn = self.cookies['info'].split(' : ')
 62             except:
 63                 self.who = self.fn = self.cookies['info']
 64                 langStr = ' '
 65             self.langs = langStr.split(',')
 66         else:
 67             self.who = self.fn = ' '
 68             self.langs = ['Python']
 69 
 70     def showForm(self):
 71         self.getCPPCookies()
 72 
 73         # Put together language checkboxes
 74         langStr = []
 75         for eachLang in AdvCGI.langSet:
 76             # Add CHECKED if language name exists in cookies
 77             langStr.append(AdvCGI.langItem % (eachLang, 'CHECKED' if eachLang in self.langs else '', eachLang))
 78 
 79         # See if user cookie set up yet
 80         if not ('user' in self.cookies and self.cookies['user']):
 81             cookStatus = '<i>(cookies has not been set yet)</i>'
 82             userCook = ''
 83         else:
 84             userCook = cookStatus = self.cookies['user']
 85 
 86         print('%s%s' % (AdvCGI.header, AdvCGI.formhtml % (AdvCGI.url, cookStatus, 
 87                         userCook, self.who, ''.join(langStr), self.fn)))
 88 
 89     errhtml = '''<html><head><title>
 90 Advanced CGI Demo</title></head>
 91 <body><h3>Error</h3>
 92 <b>%s</b><p>
 93 <form><input type=button value=back onclick='window.history.back()'></form>
 94 </body></html>'''
 95 
 96     def showError(self):
 97         print(AdvCGI.header + AdvCGI.errhtml % (self.error))
 98 
 99     # Some html tags:
100     #   <li>: for list
101     #   <ol>: odered list
102     #   <ul>: unodered list
103     #   <br>: newline
104     reshtml = '''<html><head><title>
105 Advanced CGI Demo</title></head>
106 <body><h2>Your Uploaded Data</h2>
107 <h3>Your cookie value is: <b>%s</b></h3>
108 <h3>Your name is: <b>%s</b></h3>
109 <h3>You can program in the following languages:</h3>
110 <ul>%s</ul>
111 <h3>Your uploaded file...<br>
112 Name: <i>%s</i><br>
113 Contents:</h3>
114 <pre>%s</pre>
115 Click <a href="%s"><b>here</b></a> to return to form.
116 </body></html>'''
117     
118     # Tell client to store cookies
119     def setCPPCookies(self):
120         for eachCookie in self.cookies.keys():
121             print('Set-cookie: CPP%s=%s; path=/' % (eachCookie, quote(self.cookies[eachCookie])))
122 
123     # Display results page
124     def doResults(self):
125         MAXBYTES = 4096
126         langList = ''.join('<li>%s<br>' % eachLang for eachLang in self.langs)
127         filedata = self.fp.read(MAXBYTES)
128         # Check file size
129         if len(filedata) == MAXBYTES and self.fp.read():
130             filedata = '%s%s' % (filedata, 
131                 '...<b><i>(file truncated due to size)</i></b>')
132         self.fp.close()
133         if filedata == '':
134             filedata = '<b><i>(file not given or upload error)</i></b>'
135         filename = self.fn
136 
137         # See if user cookie set up yet
138         if not ('user in self.cookies and self.cookies["user"]'):
139             cookStatus = '<i>(cookie has not been set yet)</i>'
140             userCook = ''
141         else:
142             userCook = cookStatus = self.cookies['user']
143 
144         # Set cookies
145         # Use ' : ' rather than ':' to join, because filename may contains ':' like 'c:\windows\...'
146         self.cookies['info'] = ' : '.join((self.who, ','.join(self.langs), filename))
147         self.setCPPCookies()
148 
149         print('%s%s' % (AdvCGI.header, AdvCGI.reshtml % (cookStatus, self.who, langList,
150                             filename, filedata, AdvCGI.url)))
151 
152     # Determine which page to return
153     def go(self):
154         self.cookies = {}
155         self.error = ''
156         form = FieldStorage()
157         # No form received
158         if not form.keys():
159             self.showForm()
160             return
161 
162         if 'person' in form:
163             self.who = form['person'].value.strip().title()
164             if self.who == '':
165                 self.error = 'Your name is required. (blank)'
166         else:
167             self.error = 'Your name is required. (missing)'
168 
169         self.cookies['user'] = unquote(form['cookie'].value.strip()) if 'cookie' in form else ''
170         if 'lang' in form:
171             langData = form['lang']
172             if isinstance(langData, list):
173                 self.langs = [eachLang.value for eachLang in langData]
174             else:
175                 self.langs = [langData.value]
176         else:
177             self.error = 'At least one language required.'
178 
179         if 'upfile' in form:
180             upfile = form['upfile']
181             # form['upfile'] ->.filename for file name, .file for file data
182             self.fn = upfile.filename or ''
183             if upfile.file:
184                 self.fp = upfile.file
185             else:
186                 self.fp = StringIO('(no data)')
187         else:
188             # StringIO as data container
189             self.fp = StringIO('(no file)')
190             self.fn = ''
191 
192         if not self.error:
193             self.doResults()
194         else:
195             self.showError()
196 
197 if __name__ == '__main__':
198     page = AdvCGI()
199     page.go()

View Code

首先连接到服务器打开页面能够观察下图所示界面,

起名 16

 

图中得以看来,页面包含三个cooike信息,用户名可选填项,你的名字必选项,多语言复选项以及需求上传的文书选取。

当不填写名字或未勾选内容时,会回来如下的错误新闻页面。

起名 17

起名 18

填好消息后得以看出结果页面展现了选填的新闻,并且出示了上传文件的内容。

起名 19

点击here按钮会回到从前的页面,同时鉴于cookie的存在,在此之前填入的音讯都被保存了下来。

起名 20

 

分层解析
第1导入所需的模块,cgi用于拍卖cgi交互,environ用于查看当前环境变量,主要用来查看HTTP_老板KIE使用,StringIO可看成字符串容器,最终的quote和unquote函数用于转移特定字符。

1 from cgi import FieldStorage
2 from os import environ
3 from io import StringIO
4 from urllib.parse import quote, unquote

紧接着定义一个AdvCGI类,设置通用的头顶参数和url,以及表单页面(在那之中表单中定义了multipart编码方式以福利文件上传),表单语言输入项,checkbox的html片段。

 1 class AdvCGI(object):
 2     header = 'Content-Type: text/html\n\n'
 3     url = '/cgi-bin/cgi_advanced.py'
 4 
 5     formhtml = '''<html><head><title>
 6 Advanced CGI Demo</title></head>
 7 <body><h2>Advanced CGI Demo Form</h2>
 8 <form method=post action="%s" enctype="multipart/form-data">
 9 <h3>My Cookie Setting</h3>
10 <li><code><b>CPPuser = %s</b></code>
11 <h3>Enter cookie value<br>
12 <input name=cookie value="%s"> (<i>optional</i>)</h3>
13 <h3>Enter your name<br>
14 <input name=person value="%s"> (<i>required</i>)</h3>
15 <h3>What languages can you program in?
16 (<i>at least one required<i>)</h3>
17 %s
18 <h3>Enter file to upload <small>(max size 4K)</small></h3>
19 <input type=file name=upfile value="%s" size=45>
20 <p><input type=submit>
21 </form></body></html>'''
22 
23     langSet = ('Python', 'Ruby', 'Java', 'C++', 'PHP', 'C', 'JavaScript')
24     # Set checkbox for language items,
25     # First %s for real value, second one for CHECKED or not, third one for presented value
26     langItem = '<input type=checkbox name=lang value="%s"%s> %s\n'

在类中定义一个从客户端获取cookie的不二等秘书籍,首先采用os.environ类查看是或不是包涵HTTP_首席营业官KIE参数,固然有则表达包涵cookie消息,通过os.environ[‘HTTP_COOKIE’]能够博获得cookie的音信,那几个类的施用方式接近于字典,也存有*.keys()方法。当前示范中取获得的cookie大约为如下格式‘CPPinfo=Like%三APython%2CJava%三AC%三A\path…;
CPPuser=Self’,其中%3A为冒号‘:’,%2C分号为‘;’。

Note:
浏览器发送给客户端设置cookie的头顶格式为Set-库克ie,浏览器响应底部为Cookie。

在赢得cookie的形式中首要性对cookie作了之类的处理,

  1. 判定是还是不是有cookie的存在,有则实施cookie操作;
  2. 依据支行对cookie进行split操作,分开cookie的每1对属性键值,并拓展遍历;
  3. 在遍历中,质量评定CPP开头,获取CPP后肆(叁:七)位作为标签,获取五个人之后为属性值;
  4. 尚未cookie则设置为空;
  5. 看清cookie中的info字段是或不是为空,不为空则利用‘
    :
    ’实行分割,此处由于有门路信息,大概存在多余冒号,由此在切分特征的冒号前后投入空格实行区分;
  6. 将新闻切分获得用户名,使用语言,上传文件路径三个音信,再对里面包车型地铁选取语言按逗号实行剪切,从而获取具有音讯。

    1 # Read cookies from client
    2 def getCPPCookies(self):
    3 # environ contains the environment info, similar to dict usage
    4 # Check whether cookie exists
    5 if ‘HTTP_COOKIE’ in environ:
    6 # environ[‘HTTP_COOKIE’] could be like: ‘CPPinfo=Like%3APython%2CJava%3AC%3A\path…; CPPuser=Self’
    7 # %3A -> :
    8 # %2C -> ,
    9 cookies = [x.strip() for x in environ[‘HTTP_COOKIE’].split(‘;’)]
    10 # cookies = [‘CPPinfo=Like%3APython%2CJava%3AC%3A\path…’, ‘CPPuser=Self’]
    11 for eachCookie in cookies:
    12 if len(eachCookie) > 6 and eachCookie[:3]==’CPP’:
    13 # tag -> info / user
    14 tag = eachCookie[3:7]
    15 try:
    16 self.cookies[tag] = eval(unquote(eachCookie[8:]))
    17 except (NameError, SyntaxError):
    18 self.cookies[tag] = unquote(eachCookie[8:])
    19 if ‘info’ not in self.cookies:
    20 self.cookies[‘info’] = ”
    21 if ‘user’ not in self.cookies:
    22 self.cookies[‘user’] = ”
    23 else:
    24 self.cookies[‘info’] = self.cookies[‘user’] = ”
    25
    26 if self.cookies[‘info’] != ”:
    27 print(self.cookies[‘info’])
    28 try:
    29 self.who, langStr, self.fn = self.cookies[‘info’].split(‘ : ‘)
    30 except:
    31 self.who = self.fn = self.cookies[‘info’]
    32 langStr = ‘ ‘
    33 self.langs = langStr.split(‘,’)
    34 else:
    35 self.who = self.fn = ‘ ‘
    36 self.langs = [‘Python’]

概念贰个出示表单的秘诀,用于初次页面包车型地铁来得应用,首先获得服务器cookie信息,设置语言表单,再检查评定cookie是还是不是加载,最终回来整个展现表单页面。

 1     def showForm(self):
 2         self.getCPPCookies()
 3 
 4         # Put together language checkboxes
 5         langStr = []
 6         for eachLang in AdvCGI.langSet:
 7             # Add CHECKED if language name exists in cookies
 8             langStr.append(AdvCGI.langItem % (eachLang, 'CHECKED' if eachLang in self.langs else '', eachLang))
 9 
10         # See if user cookie set up yet
11         if not ('user' in self.cookies and self.cookies['user']):
12             cookStatus = '<i>(cookies has not been set yet)</i>'
13             userCook = ''
14         else:
15             userCook = cookStatus = self.cookies['user']
16 
17         print('%s%s' % (AdvCGI.header, AdvCGI.formhtml % (AdvCGI.url, cookStatus, 
18                         userCook, self.who, ''.join(langStr), self.fn)))

安装错误提示页面包车型地铁html代码,并定义显示错误页面包车型客车函数,

1     errhtml = '''<html><head><title>
2 Advanced CGI Demo</title></head>
3 <body><h3>Error</h3>
4 <b>%s</b><p>
5 <form><input type=button value=back onclick='window.history.back()'></form>
6 </body></html>'''
7 
8     def showError(self):
9         print(AdvCGI.header + AdvCGI.errhtml % (self.error))

安装再次回到页面包车型客车html,个中html标签<li>设置列表成分,<ol>为有连串表,<ul>为冬天列表,<br>换行呈现。

 1     # Some html tags:
 2     #   <li>: for list
 3     #   <ol>: odered list
 4     #   <ul>: unodered list
 5     #   <br>: newline
 6     reshtml = '''<html><head><title>
 7 Advanced CGI Demo</title></head>
 8 <body><h2>Your Uploaded Data</h2>
 9 <h3>Your cookie value is: <b>%s</b></h3>
10 <h3>Your name is: <b>%s</b></h3>
11 <h3>You can program in the following languages:</h3>
12 <ul>%s</ul>
13 <h3>Your uploaded file...<br>
14 Name: <i>%s</i><br>
15 Contents:</h3>
16 <pre>%s</pre>
17 Click <a href="%s"><b>here</b></a> to return to form.
18 </body></html>'''

概念多少个安装cookie的点子,用于将set
cookie尾部发送给客户端来保存cookie,

1     # Tell client to store cookies
2     def setCPPCookies(self):
3         for eachCookie in self.cookies.keys():
4             print('Set-cookie: CPP%s=%s; path=/' % (eachCookie, quote(self.cookies[eachCookie])))

概念一个赶回展现页面包车型地铁艺术,首要进度如下,

  1. 率先设置上传文件的最大范围为肆k,对文件进行读取,只彰显文件的前四k长度;
  2. 文件不存在则显得无上传文件;
  3. 检查评定用户cookie音信是还是不是存在,重回相应的展示;

    1 # Display results page
    2 def doResults(self):
    3 MAXBYTES = 4096
    4 langList = ”.join(‘

  4. %s
    ‘ % eachLang for eachLang in self.langs)
    5 filedata = self.fp.read(MAXBYTES)
    6 # Check file size
    7 if len(filedata) == MAXBYTES and self.fp.read():
    8 filedata = ‘%s%s’ % (filedata,
    9 ‘…(file truncated due to size)‘)
    10 self.fp.close()
    11 if filedata == ”:
    12 filedata = ‘(file not given or upload error)
    13 filename = self.fn
    14
    15 # See if user cookie set up yet
    16 if not (‘user in self.cookies and self.cookies[“user”]’):
    17 cookStatus = ‘(cookie has not been set yet)
    18 userCook = ”
    19 else:
    20 userCook = cookStatus = self.cookies[‘user’]
    21
    22 # Set cookies
    23 # Use ‘ : ‘ rather than ‘:’ to join, because filename may contains ‘:’ like ‘c:\windows…’
    24 self.cookies[‘info’] = ‘ : ‘.join((self.who, ‘,’.join(self.langs), filename))
    25 self.setCPPCookies()
    26
    27 print(‘%s%s’ % (AdvCGI.header, AdvCGI.reshtml % (cookStatus, self.who, langList,
    28 filename, filedata, AdvCGI.url)))

提及底定义2个go方法,包蕴了全部实施流程的决定,

  1. 变迁表单实例,开首化cookie和错误消息为空;
  2. 检查测试form中是不是有关键字,假若未有则印证表单form为空,是第四回呼吁,调用展现界面方法;
  3. 假诺表单中有请求字段,则获得字段,举办拍卖,若person字段值为空则设置错误消息;
  4. 安装user的值,假使未有则填入空字符串;
  5. 检查实验勾选的语言项,借使未有勾选则设置错误音信。此处用到了多值字段,即多选时则对form[‘lang’]拓展遍历后再取值;
  6. 查看文件新闻,根据文件实行操作;
  7. 谈到底遵照是不是有错误音讯决定回来结果页面或错误提醒页面。

 

 1     # Determine which page to return
 2     def go(self):
 3         self.cookies = {}
 4         self.error = ''
 5         form = FieldStorage()
 6         # No form received
 7         if not form.keys():
 8             self.showForm()
 9             return
10 
11         if 'person' in form:
12             self.who = form['person'].value.strip().title()
13             if self.who == '':
14                 self.error = 'Your name is required. (blank)'
15         else:
16             self.error = 'Your name is required. (missing)'
17 
18         self.cookies['user'] = unquote(form['cookie'].value.strip()) if 'cookie' in form else ''
19         if 'lang' in form:
20             langData = form['lang']
21             if isinstance(langData, list):
22                 self.langs = [eachLang.value for eachLang in langData]
23             else:
24                 self.langs = [langData.value]
25         else:
26             self.error = 'At least one language required.'
27 
28         if 'upfile' in form:
29             upfile = form['upfile']
30             # form['upfile'] ->.filename for file name, .file for file data
31             self.fn = upfile.filename or ''
32             if upfile.file:
33                 self.fp = upfile.file
34             else:
35                 self.fp = StringIO('(no data)')
36         else:
37             # StringIO as data container
38             self.fp = StringIO('(no file)')
39             self.fn = ''
40 
41         if not self.error:
42             self.doResults()
43         else:
44             self.showError()
45 
46 if __name__ == '__main__':
47     page = AdvCGI()
48     page.go()

 

3
服务器网关接口WSGI / Web Server Gateway Interface

3.1
WSGI简介

PythonWeb服务器网关接口(Web
Server Gateway
Interface)是Python应用程序或框架Web服务器以内的1种接口,近期被广泛接受,然而WSGI并不曾法定的落到实处,因为WSGI更像是贰个说道,遵照协议的明显,WSGI的应用程序即能够在此外服务器上运维,WSGI的是遵照现存的CGI标准而设计的。

WSGI标准在PEP33三中实行了定义,近来司空眼惯框架已兑现,包罗django框架。

3.二WSGI使用示例

在此对WSGI的利用实行简易的牵线,主要不外乎两部分,app和服务器,代码如下,

App

 1 """
 2 Run server
 3 Connect to http://localhost:8000/
 4 """
 5 
 6 def simple_wsgi_app(environ, start_response):
 7     status = '200 OK'
 8     headers = [('Content-type', 'text/plain')]
 9     # This function pass status code and header, status code/header decided inside wsgi app
10     start_response(status, headers)
11     return [b'Hello world']

上边的代码中率先定义三个简约的WSGI的app程序,对于这么些app程序,要求将其扩散给服务器,由此WSGI规定这么些流传的app程序须要经受五个参数,

先是个参数是environ,为带有环境变量的字典,

首个参数start_response为2个可调用对象,这些指标要求能够将HTTP的状态码(40x/50x)以及底部消息等回到给浏览器。

最后函数还应有回到四个可迭代对象,个中包蕴了归来给浏览器客户端的新闻(HTML等)。

服务器

在完毕地点的粗略app后,接下去分析不难服务器的基本运作进程,这么些服务器会吸收接纳三个参数,即在此之前涉嫌的environ,和app参数,在在那之中间定义了start_response()函数,接收状态码和尾部音讯,最终回来三个write的可进行对象。

在服务器内会将start_response函数和environ参数传给app举办实施,最后采用write对象把新闻重回给客户端。

 1 from io import StringIO
 2 import sys
 3 
 4 def simple_wsgi_server(app, environ=None):
 5     sio = StringIO()
 6 
 7     def start_response(status, headers):
 8         sio.write('Status: %s\r\n' % status)
 9         for header in headers:
10             sio.write('%s: %s\r\n' % header)
11         return sio.write
12 
13     iterable = app(environ, start_response)
14     try:
15         if not sio.getvalue():
16             raise RuntimeError("start_response() not called by app!")
17         sio.write('\r\n%s\r\n' % '\r\n'.join(str(line) for line in iterable))
18     finally:
19         if hasattr(iterable, 'close') and callable(iterable.close):
20             iterable.close()
21 
22     sys.stdout.write(sio.getvalue())
23     sys.stdout.flush()

 

此处还提供了3个粗略的WSGI的服务器和示例app,直接导入模块即能够展开应用。当然在app程序的挑选上得以采用提供的demo_app也得以选取自定义的app。自定义的app最后回到hello
world,而示例的demo_app还会回到参数新闻。

 1 from wsgiref.simple_server import make_server, demo_app
 2 def wsgi_server(app):
 3     httpd = make_server('', 8000, app)
 4     print('Started app serving on port 8000...')
 5     httpd.serve_forever()
 6 
 7 em_app = False
 8 em_server = True
 9 wsgi_app = demo_app if em_app else simple_wsgi_app
10 wsgi_server = wsgi_server if em_server else simple_wsgi_server

运营服务器后,输入url链接:
http://localhost:8000/,能够赢得再次来到的界面如下,

起名 21

参照链接


《Python 大旨编程第叁版》

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图