阅读本文大概需要 3.5分钟。

写了几年 python web 开发,却还不知道WSGI是什么东西,是不是大有人在。说来也正常,因为作为开发者很少需要去了解wsgi是什么,也能把网站做出来。

但是如果你想自己写个web框架玩玩,就不得不去了解wsgi了。

回顾一下,我们在用python做web开发的时候,一般基于某个web框架来开发,django或者是flask等其它框架。业务开发完成后,就要部署到某台服务器中提供对外的访问。这时候你去网上一搜,他们都会告诉你需要用 gunicorn或者是uwsgi 来部署。那么gunicorn、uwsgi 又是什么玩意。

看这个图你就明白了

这里的uwsgi或者gunicorn扮演的角色就是web服务器的角色,这里的服务器是软件层面的服务器,用于处理浏览器发过来的HTTP请求以及将响应结果返回给前端。而Web框架的主要任务就是处理业务逻辑生成结果给web服务器,再由web服务器返回给浏览器。

而web框架和web服务器之间的通信需要遵循一套规范,这个规范就是WSGI了。

为什么要搞这么一套规范出来?规范就是为了统一标准,方便大家所用

想象一下,我们手机充电的接口现在都是Type-c的,Type-c 就是一种规范, 手机厂商按照这个规范去生产手机, 充电器厂商按照Type-c的规范生产充电器,不同厂商的手机就可以和不同厂商的充电器搭配使用。而苹果却自成一套规范,最后导致Android充电器无法给苹果充电。


那如何写出一个符合 WSGI规范的应用(框架)程序和服务器呢?

如上图所示,左边是web服务器,右边是web框架,或者说应用程序。

应用程序

WSGI规定应用程序必须是一个可调用对象(可调用对象可以是函数,也可以是类,还可以是实现了 __call__的实例对象),而且必须接受两个参数,该对象的返回值必须是可迭代对象。

我们可以写个最简单的应用程序的例子

HELLO_WORLD = b"Hello world!\n"def application(environ, start_response):    status = '200 OK'    response_headers = [('Content-type', 'text/plain')]    start_response(status, response_headers)return [HELLO_WORLD]

代码可左右滑动

application 是一个函数,肯定是可调用对象,然后接收两个参数,两个参数分别是:environ和start_response

  • environ是一个字典,里面储存了HTTP request相关的所有内容,比如header、请求参数等等

  • start_response是一个WSGI 服务器传递过来的函数,用于将response header,状态码传递给Server。

调用 start_response 函数负责将响应头、状态码传递给服务器, 响应体则由application函数返回给服务器, 一个完整的http response 就由这两个函数提供。

但凡是实现了wsgi的web框架都会有这样一个可调用对象

服务器

WSGI 服务器端做的事情就是每次接收HTTP请求,构建environ对象,然后调用application对象,最后将HTTP Response返回给浏览器。

下面就是一个完整的wsgi server 的代码

import socketimport sysfrom io import StringIOclass WSGIServer(object):    address_family = socket.AF_INET    socket_type = socket.SOCK_STREAM    request_queue_size = 1    def __init__(self, server_address):# Create a listening socket        self.listen_socket = listen_socket = socket.socket(            self.address_family,            self.socket_type        )# Allow to reuse the same address        listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# Bind        listen_socket.bind(server_address)# Activate        listen_socket.listen(self.request_queue_size)# Get server host name and port        host, port = self.listen_socket.getsockname()[:2]        self.server_name = socket.getfqdn(host)        self.server_port = port# Return headers set by Web framework/Web application        self.headers_set = []    def set_app(self, application):        self.application = application    def serve_forever(self):        listen_socket = self.listen_socketwhile True:# New client connection            self.client_connection, client_address = listen_socket.accept()# Handle one request and close the client connection. Then# loop over to wait for another client connection            self.handle_one_request()    def handle_one_request(self):        self.request_data = request_data = self.client_connection.recv(1024)# Print formatted request data a la 'curl -v'print(''.join('.format(line=line)for line in request_data.splitlines()        ))        self.parse_request(request_data)# Construct environment dictionary using request data        env = self.get_environ()# It's time to call our application callable and get# back a result that will become HTTP response body        result = self.application(env, self.start_response)# Construct a response and send it back to the client        self.finish_response(result)    def parse_request(self, text):        request_line = text.splitlines()[0]        request_line = request_line.rstrip('\r\n')# Break down the request line into components        (self.request_method,  # GET         self.path,  # /hello         self.request_version  # HTTP/1.1         ) = request_line.split()    def get_environ(self):        env = {}# The following code snippet does not follow PEP8 conventions# but it's formatted the way it is for demonstration purposes# to emphasize the required variables and their values## Required WSGI variables        env['wsgi.version'] = (1, 0)        env['wsgi.url_scheme'] = 'http'        env['wsgi.input'] = StringIO.StringIO(self.request_data)        env['wsgi.errors'] = sys.stderr        env['wsgi.multithread'] = False        env['wsgi.multiprocess'] = False        env['wsgi.run_once'] = False# Required CGI variables        env['REQUEST_METHOD'] = self.request_method  # GET        env['PATH_INFO'] = self.path  # /hello        env['SERVER_NAME'] = self.server_name  # localhost        env['SERVER_PORT'] = str(self.server_port)  # 8888return env    def start_response(self, status, response_headers, exc_info=None):# Add necessary server headers        server_headers = [            ('Date', 'Tue, 31 Mar 2015 12:54:48 GMT'),            ('Server', 'WSGIServer 0.2'),        ]        self.headers_set = [status, response_headers + server_headers]# To adhere to WSGI specification the start_response must return# a 'write' callable. We simplicity's sake we'll ignore that detail# for now.# return self.finish_response    def finish_response(self, result):        try:            status, response_headers = self.headers_set            response = 'HTTP/1.1 {status}\r\n'.format(status=status)for header in response_headers:                response += '{0}: {1}\r\n'.format(*header)            response += '\r\n'for data in result:                response += data# Print formatted response data a la 'curl -v'print(''.join('> {line}\n'.format(line=line)for line in response.splitlines()            ))            self.client_connection.sendall(response)        finally:            self.client_connection.close()SERVER_ADDRESS = (HOST, PORT) = 'localhost', 8080def make_server(server_address, application):    server = WSGIServer(server_address)    server.set_app(application)return serverif __name__ == '__main__':    httpd = make_server(SERVER_ADDRESS, application)print('WSGIServer: Serving HTTP on port {port} ...\n'.format(port=PORT))    httpd.serve_forever()

代码可左右滑动

当然,如果只是写个用于开发环境用的server,用不着这么麻烦自己造轮子,因为python内置模块中就提供有 wsgi server 的功能。

from wsgiref.simple_server import make_serversrv = make_server('localhost', 8080, application)srv.serve_forever()

只要3行代码就可以提供wsgi服务器,是不是超级方便,最后来访问测试下浏览器发起一个请求的效果

以上就是关于wsgi的简介,深入了解wsgi可以熟悉下PEP333

原创不易,点赞再看转发三连

does not name a type是什么意思_科普:WSGI 是什么,看完保证懂相关推荐

  1. type c pin定义_在C中定义宏以设置和清除PIN的位

    type c pin定义 Given a PIN (value in HEX) and bit number, we have to SET and then CLEAR given bit of t ...

  2. argument type mismatch怎么解决_怎么做好GMAT 的CR?

    先思考自己欠缺在哪,再思考怎么解决,cr错误率高,无非2个点. 1.文本理解有问题,对题目文本理解不到位,出现信息遗漏跟信息偏差.比如一个题说的是昆虫喜欢在有光的地方聚集,就不要读出昆虫喜欢光. 2. ...

  3. c type 笔记本 芯片方案_开发USB Type-C的注意事项及各芯片厂商的方案解读

    一条USB数据线无非就是一条线加两个头,这看似简单,但却没有想象中的简单,小小的数据线,隐藏着许多你可能不知道的知识,而USB Type-C的横空问世更是说明了不能小瞧它. 正反向可接插的USB Ty ...

  4. c type 笔记本 芯片方案_主流笔记本Type-C情况(持续更新)

    08主流笔记本Type-C情况(持续更新) 与上一页相同,本页作为最后一页,也将持续更新,随着大家的内容提供而不断更新. 基于大家对于笔记本Type-C实在是难以区分其功能和意义,这一页主要为大家做一 ...

  5. c type 笔记本 芯片方案_请问笔记本的type-c接口有什么作用?

    更新: 后来专门整理了一下相关的知识,写了一篇科普文章,感兴趣的读者可以直接去看,相比这个回答要完善一些: ----------------分割线------------------- Type-C接 ...

  6. golang type 说明和使用

    我对type不了解,因为我没有完整的看完一本讲golang的书,我学习golang的过程基本都是在看源码的过程中,遇到不懂得先猜一下,后续有时间去查一查这个概念. 1.type 和 struct 我最 ...

  7. 大批量生成假数据,faker.js获得近28k个Star

    整理 | 夕颜 图源 | 视觉中国 来源 | CSDN(ID:CSDNnews) 近日,GitHub上一个生成假数据的项目faker.js火了,攀升Trendinging榜单第二,标星目前已超过27. ...

  8. 如何利用自定义注解放行 Spring Security 项目的接口

    在实际项目中使用到了springsecurity作为安全框架,我们会遇到需要放行一些接口,使其能匿名访问的业务需求.但是每当需要当需要放行时,都需要在security的配置类中进行修改,感觉非常的不优 ...

  9. Spring Boot 最核心的 3 个注解详解

    最近面试一些 Java 开发者,他们其中有些在公司实际用过 Spring Boot, 有些是自己兴趣爱好在业余自己学习过. 然而,当我问他们 Spring Boot 最核心的 3 个注解是什么,令我失 ...

最新文章

  1. sqlite3 多线程 c语言,sqlite3 c语言编程 之 三个基本函数
  2. Caffe实践】如何利用Caffe训练ImageNet分类网络
  3. Android 监听ScrollView的滑动
  4. 关于需求管理的胡思乱想---R3PR
  5. Java有序表查找:折半查找、二分查找、差值查找和斐波那契查找
  6. git设置mergetool可视化工具
  7. 云计算开发学习笔记:Python3迭代器与生成器
  8. AC日记——[USACO10MAR]仓配置Barn Allocation 洛谷 P1937
  9. 小米这个系列绝了!7款之后再添新机,完全分不清
  10. IPOP下的tcl脚本
  11. Word 2007~2010手动双面打印设置
  12. html把div做成透明背景,DIV半透明层 CSS来实现网页背景半透明
  13. 微信订阅号简易开发——小白攻略图文版
  14. OSPF协议介绍➌(认证、汇总扩展、LSDB的保护特性、缺省路由、附录E、选路规则、SPF算法、NP+E位、FA地址)
  15. (信贷风控十一)随机森林在催收评分卡还款率模型的应用(python代码实现)
  16. matlab与数学实验心得体会,数学matlab实验心得体会
  17. 前端笔记之移动端响应式(中)视口百分比布局弹性盒模型remfillpage
  18. 2022年总结 | 从初二学生到算法作者的蜕变之路
  19. 怎么开始学一门计算机语言有哪些,如何学习(自学)一门编程语言
  20. 播放rtmp在线网站及播放器

热门文章

  1. 博客园在我的博客添加点击小心心特效
  2. HTML元素(标签)大全及使用说明 (整)
  3. DevExpress 汉化(简单、实用、快速) 转
  4. Spring启动NoClassDefFoundError中EmbeddedValueResolver错误
  5. 和我一起打造个简单搜索之ElasticSearch入门
  6. 智·御未来 亚信安全巡展·2017即将起航
  7. node.js 事件循环
  8. bootstrap下的双选时间插件使用方法
  9. 《设计模式解析(第2版•修订版)》—第1章 1.4节应对变化:使用功能分解
  10. OSPF NSSA 默认路由的问题