了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:

  1. 浏览器发送一个HTTP请求;

  2. 服务器收到请求,生成一个HTML文档;

  3. 服务器把HTML文档作为HTTP响应的Body发送给浏览器;

  4. 浏览器收到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。

WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。我们来看一个最简单的Web版本的“Hello, web!”:

def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']

上面的application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

  • environ:一个包含所有HTTP请求信息的dict对象;

  • start_response:一个发送HTTP响应的函数。

在application()函数中,调用:

start_response('200 OK', [('Content-Type', 'text/html')])

就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。

通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。

然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。

有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML,通过start_response()发送Header,最后返回Body。

整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。

不过,等等,这个application()函数怎么调用?如果我们自己调用,两个参数environ和start_response我们没法提供,返回的bytes也没法发给浏览器。

所以application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。但是现在,我们只想尽快测试一下我们编写的application()函数真的可以把HTML输出到浏览器,所以,要赶紧找一个最简单的WSGI服务器,把我们的Web应用程序跑起来。

好消息是Python内置了一个WSGI服务器,这个模块叫wsgiref,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。

运行WSGI服务

我们先编写hello.py,实现Web应用程序的WSGI处理函数:

# hello.py

def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, web!</h1>']

然后,再编写一个server.py,负责启动WSGI服务器,加载application()函数:

# server.py
# 从wsgiref模块导入:
from wsgiref.simple_server import make_server
# 导入我们自己编写的application函数:
from hello import application # 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')
# 开始监听HTTP请求:
httpd.serve_forever()

确保以上两个文件在同一个目录下,然后在命令行输入python server.py来启动WSGI服务器:

注意:如果8000端口已被其他程序占用,启动将失败,请修改成其他端口。

启动成功后,打开浏览器,输入http://localhost:8000/,就可以看到结果了:

在命令行可以看到wsgiref打印的log信息:

按Ctrl+C终止服务器。

如果你觉得这个Web应用太简单了,可以稍微改造一下,从environ里读取PATH_INFO,这样可以显示更加动态的内容:

# hello.py

def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
body = '<h1>Hello, %s!</h1>' % (environ['PATH_INFO'][1:] or 'web')
return [body.encode('utf-8')]

你可以在地址栏输入用户名作为URL的一部分,将返回Hello, xxx!:

是不是有点Web App的感觉了?

小结

无论多么复杂的Web应用程序,入口都是一个WSGI处理函数。HTTP请求的所有输入信息都可以通过environ获得,HTTP响应的输出都可以通过start_response()加上函数返回值作为Body。

复杂的Web应用程序,光靠一个WSGI函数来处理还是太底层了,我们需要在WSGI之上再抽象出Web框架,进一步简化Web开发。

参考源码

hello.py

do_wsgi.py

Python Web Server Gateway Interface

原文地址:https://www.python.org/dev/peps/pep-0333/

Python Web Server Gateway Interface -- WSGI的更多相关文章

  1. a simple and universal interface between web servers and web applications or frameworks: the Python Web Server Gateway Interface (WSGI).

    WSGI is the Web Server Gateway Interface. It is a specification that describes how a web server comm ...

  2. python web server gateway interface (wsgi ) notes

    前言: 注:如果需要得到支持批Python3.x以及包含了勘误表,附录,和说明的更新版规范,请查看PEP 3333 摘要: 这篇文档详细说明了一套在web服务器与Python web应用程序(web框 ...

  3. Notes on PEP333 (Python Web Server Gateway Interface)

    This note is about PEP3333- Python Web Server Gateway Interface. Refer to (Source: http://legacy.pyt ...

  4. 【Python Programe】WSGI (Web Server Gateway Interface)

    Part1: What is a Web server? 一个位于物理服务器上的网络服务器(服务器里的服务器),等待客户端去发送request,当服务器接收到request,就会生成一个respons ...

  5. Python的WSGI(Web Server Gateway Interface)服务器

    Python的WSGI(Web Server Gateway Interface)服务器 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任.

  6. Python Web开发中的WSGI协议简介

    在Python Web开发中,我们一般使用Flask.Django等web框架来开发应用程序,生产环境中将应用部署到Apache.Nginx等web服务器时,还需要uWSGI或者Gunicorn.一个 ...

  7. Python Web开发中,WSGI协议的作用和实现原理详解

    首先理解下面三个概念: WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python模块,框架,API或者任何软件,只是一种规范,描述web server ...

  8. 小测几种python web server的性能

    http://blog.csdn.net/raptor/article/details/8038476 因为换了nginx就不再使用mod_wsgi来跑web.py应用了,现在用的是gevent-ws ...

  9. C# 启动 a Python Web Server with Flask

    概览 最近有个需求是通过c#代码来启动python 脚本.嘿~嘿!!! 突发奇想~~既然可以启动python脚本,那也能启动flask,于是开始着手操作. 先看一波gif图 通过打开控制台启动flas ...

随机推荐

  1. boost-断言

    标准assert宏的原型声明在<assert.h>中,其作用是如果它的测试条件为假,则调用abort()终止程序执行,程序退出的时候会弹出一个错误提示框,并向控制台输出所在文件及行号.as ...

  2. vba遗传算法之非一致性突变

    http://www.docin.com/p-959323141-f4.html Sub 非一致性变异() Dim totalGenerate As Integer, currentGenerate ...

  3. java学习路线图(2018年最新版)

    最近有些网友问我如何自学 Java 后端,还有些是想从别的方向想转过来,但都不太了解 Java 后端究竟需要学什么,究竟要从哪里学起,哪些是主流的 Java 后端技术等等,导致想学,但又很迷茫,不知从 ...

  4. BZOJ 4765 普通计算姬 (分块 + BIT)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1547  Solved: 329[Submit][Status][Discus ...

  5. jQuery length 和 size()区别

    jQuery length和size()区别总结如下: 1.length是属性,size()是方法. 2.如果你只是想获取元素的个数,两者效果一样既 $("img").length ...

  6. Ubuntu Server 命令行下的默认语言改为英语en_US.UTF-8

    源文链接:http://tonychiu.blog.51cto.com/656605/393131 如果Ubuntu Server在安装过程中,选择的是中文(很多新手都会在安装时选择中文,便于上手), ...

  7. 动态生成PictureBox控件,涉及:PictureBox控件和flowLayoutPanel面板

    一.概述 flowLayoutPanel面板是一系列控件的容器,有关详细的使用方法留待以后总结. 二.问题提出 问题提出:点击按钮,扫描指定文件夹并将其中的所有图片放在flowLayoutPanel面 ...

  8. PAT甲级 1120. Friend Numbers (20)

    1120. Friend Numbers (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Two in ...

  9. Hdu1054 Strategic Game(最小覆盖点集)

    Strategic Game Problem Description Bob enjoys playing computer games, especially strategic games, bu ...

  10. All Start Here.

    缘由 本博客是为天大软院 2016 级研一课程"现代软件工程"的课程设计而开设.同时借此机会和同学们进行技术交流与分享. 我们小组共有四位成员: 陈岩岩 2016218020 刘莞 ...