自己动手撸Python框架:1. WSGI简介

这个系列我们学习自己手动撸一个Web框架,参考轻量级框架web.py的实现,进行简化实现最基本功能。在实现的过程中了解Python的各种特性。

这篇文章也是自己学习的一个过程,开始之前,先介绍一下什么是WSGI(Web Server Gateway Interface),即Web服务器网关接口。WSGI本质是一个规范,定义了Web服务器如何与Python应用程序进行交互,使得使用Python写的Web应用程序可以和Web服务器对接起来。关于规范细节感兴趣的可以查看PEP3333

为什么需要WSGI?

Web部署一般采用以下方案:

  1. 部署一个Web服务器专门用来处理HTTP协议层面的各种相关任务
  2. 部署一个由某种语言(Java, PHP,Python...)开发的应用程序,这个程序从Web服务器接收客户端请求,完成处理后,再返回响应信息给Web服务器,最后通过Web服务器返回给客户端。

这个方案需要解决一个问题,Web服务器与应用服务器之间如何进行交互。为了规范Web服务器与应用程序之间的交互,最早出现的是CGI标准。WSGI是Python专用的标准,这些规范出现的目的就是统一交互规范,提高程序的可移植性。

WSGI如何工作?

在开始撸我们自己的框架之前,先了解一下WSGI是如何工作的。WSGI规范了Web服务器与Python应用程序之间的桥梁该如何搭建,这个桥梁解决以下两个问题:

1. 让Web服务器知道如何调用Python应用程序,并且把用户的请求告诉应用程序。
2. 让Python应用程序知道用户的具体请求是什么,以及如何返回结果给Web服务器。

WSGI定义了两个角色,Web服务器端称为server或者gateway,应用程序端称为application或者framework。下面我们统一使用server和application这两个术语。一般调用流程是这样的:server端会先收到用户的请求,然后会根据规范的要求调用application端,调用的结果会被封装成HTTP响应后再发送给客户端。参考如下示意图:

 例子分析

我们先看一段非常简单的代码,Python3提供了一个简单的server实现:

from wsgiref.simple_server import make_server

def application(env, start_response):
    response_body = ['%s: %s' % (k, v) for k, v in sorted(env.items())]
    response_body = '\n'.join(response_body).encode('utf-8')
    status = '200 OK'
    headers = [('Content-Type', 'text/plain'), 
               ('Content-Length', str(len(response_body)))]
    start_response(status, headers)
    return [response_body]
    
if __name__ == '__main__':
    server = make_server('localhost', 8080, application)
    server.serve_forever()
  1. make_server创建一个符合WSGI标准的服务器,使用application函数处理请求。
  2. application函数有两个参数,env封装了客户端请求信息,服务器的各种系统参数和环境变量。start_response负责把response的状态码和头部信息告诉make_server创建的服务器。
  3. server.serve_forever()启动服务器,一直处理响应。
  4. 注意:返回的内容必须是bytes类型,所以必须对字符串使用utf-8格式就行编码。

启动程序后,在浏览器输入http://localhost:8080/xxx/yyy,我们可以看到以下响应:

...
HTTP_HOST: localhost:8080
...
PATH_INFO: /xxx/yyy
...
wsgi.errors: <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>
wsgi.file_wrapper: <class 'wsgiref.util.FileWrapper'>
wsgi.input: <_io.BufferedReader name=624>
wsgi.multiprocess: False
wsgi.multithread: False
wsgi.run_once: False
wsgi.url_scheme: http
wsgi.version: (1, 0)

猜你喜欢

转载自blog.csdn.net/panda_lin/article/details/121602514