1.了解SWGI
一个Web应用的本质就是:
- 浏览器发送一个HTTP请求;
- 服务器收到请求,生成一个HTML文档;
- 服务器把HTML文档作为HTTP响应的Body发送给浏览器;
- 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。
如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。
正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务
这个接口就是WSGI:Web Server Gateway Interface
from wsgiref.simple_server import make_server,demo_app
# 提供两个必须变量
def app(environ,start_response):
# 调用start_response发送头部
from io import StringIO
#StringIO 把字符串缓存在内存中,操作函数与文件操作基本相同
stdout = StringIO()
# stdout.write('浪里个浪')
# 把字符串输出到文件中
print("Hello world,你大爷的!", file=stdout)
h = sorted(environ.items())
for k, v in h:
print(k, '=', repr(v), file=stdout)
# 响应http响应函数
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
# stdout 获取内存中缓存的全部字符串
return [stdout.getvalue().encode("utf-8")]
# 创建服务器对象 ip地址 端口号 处理http响应函数
server = make_server('0.0.0.0',9000,app)
# 启动服务器
server.serve_forever()
make_server()函数:
第一个参数:host 地址
第二个参数:端口号
第三个参数:可调用对象
- 接收两个必选参数environ、start_response,以及一个可选参数exc_info。参数名不是固定的,这就意味着你必须使用位置参数而非关键字参数(这应该是用来约束wsgi服务器的)
- environ存放CGI规定的变量一及别的变量。
- start_response 是一个可调用对象,通过类似start_response('200 OK',[('Content-Type','text/html'))来发送http的响应的头部。
- exc_info 只有start_response()被错误处理程序调用时,这个参数才会提供,并且是有应用对象提供。
返回值是字节类型的元组,用来表示http body
start_response 函数:
发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。
app函数return的返回值将作为HTTP响应的Body发送给浏览器。
注意:return app函数的返回值之前,必须调用start_response 把HTTP响应的Header返回出去。
无论多么复杂的Web应用程序,入口都是一个WSGI处理函数。HTTP请求的所有输入信息都可以通过environ获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。
可调用对象的通过类的实现方式:
class App:
def __call__(self,environ,start_response):
start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
body = '你是猪吗'
for i, j in environ.items():
body += '<p>' + (str(i) + ':::::' + str(j) + '<br><p>')
return [body.encode('utf-8')]
app = App()
# 创建服务器对象 ip地址 端口号 处理http响应函数
server = make_server('0.0.0.0',9000,app)
# 启动服务器
server.serve_forever()