您当前的位置:首页 > 电脑百科 > 程序开发 > 框架

一文秒懂Web框架基础之WSGI协议

时间:2020-11-26 12:03:52  来源:  作者:

本篇文章我们主要介绍WSGI协议,该协议用来描述Server与Framework之间的通信接口,我们日常使用的Python WEB框架Django、Flask、web.py等都遵循了该协议。下面我们就来详细了解一下该协议的实现吧!

01 简介

WSGI协议全称Web Server Gateway Interface(Web服务器网关接口)。这是Python中定义的一个网关协议,规定了Web Server如何跟应用程序交互。该协议的主要目的就是在Python中所有Web Server程序或者网关程序,能够通过统一的协议跟Web框架或者Web应用进行交互。如果没有这个协议,那每个程序都要各自实现各自的交互接口,而不能够互相兼容,重复造轮子。使用统一的协议,Web应用框架只要实现WSGI协议规范就可以与外部进行交互,不用针对某个Web Server独立开发交互逻辑。

02 Web Server实现

在了解WSGI协议之前,我们先通过socket实现一个Web服务器。通过监听本地端口来接客户端的web请求,然后进行响应,具体如下:

1. #!/usr/bin/env/ python  
2. # -*- coding:utf-8 -*-  
3.   
4. import socket  
5.   
6. END_TAG_F = b'nn'  
7. END_TAG_S = b'nrn'  
8.   
9. # 设置web server响应内容  
10. html_content = '<html><h1>My Frist Web Page<h1></html>'  
11.   
12. # 设置响应headers  
13. resp_args = ['HTTP/1.0 200 OK', 'Date: Sun, 22 nov 2020 19:00:00 GMT',  
14.              'Content-Type: text/html;charset=utf-8',  
15.              'Content-Length: {}rn'.format(len(html_content)), html_content]  
16.   
17. _resp = "rn".join(resp_args)  
18.   
19.   
20. def connet_operate(conn, addr):  
21.     """ 
22.     请求操作 
23.     :param conn:  
24.     :param addr:  
25.     :return:  
26.     """  
27.     request = b''  
28.     while END_TAG_F not in request and END_TAG_S not in request:  
29.         request += conn.recv(1024)  
30.   
31.     print("请求内容: ", request)  
32.     conn.send(_resp.encode())  
33.     conn.close()  
34.   
35.   
36. def web_server():  
37.     # socket.AF_INET用于服务器与服务器之间同行   
38.     # socket.SOCK_STREAM用于基于TCP流的通信  
39.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
40.       
41.     # 监听本地8888端口  
42.     server.bind(('127.0.0.1', 8888))  
43.     server.listen()  
44.     print("web server已经启动")  
45.   
46.     try:  
47.         while True:  
48.             conn, address = server.accept()  
49.             connet_operate(conn, address)  
50.     except:  
51.         server.close()  
52.   
53.   
54. if __name__ == "__main__":  
55.     web_server()  

下面我们启动server服务器,查看页面能不能正常访问,同时看看

一文秒懂Web框架基础之WSGI协议

 


一文秒懂Web框架基础之WSGI协议

 

上面代码就是最基本的web服务模型了,通过socket与HTTP协议提供Web服务,但上面的web服务是单线程的,只有前一个请求处理结束才处理第二个请求,我们该造一下上面的代码,通过python threading模块实现多线程的web服务器,具体操作如下:

1. #!/usr/bin/env/ python  
2. # -*- coding:utf-8 -*-  
3.   
4. import traceback  
5. import socket  
6. import errno  
7. import threading  
8.   
9. END_TAG_F = b'nn'  
10. END_TAG_S = b'nrn'  
11.   
12. # 设置web server响应内容  
13. html_content = '<html><h1>这是线程({})的页面 <h1></html>'  
14.   
15. # 设置响应headers  
16. resp_args = ['HTTP/1.0 200 OK', 'Date: Sun, 22 nov 2020 19:00:00 GMT',  
17.              'Content-Type: text/html;charset=utf-8',  
18.              'Content-Length: {}rn']  
19.   
20.   
21. def connet_operate(conn, addr):  
22.     """ 
23.     请求操作 
24.     :param conn: 
25.     :param addr: 
26.     :return: 
27.     """  
28.     request = b''  
29.     while END_TAG_F not in request and END_TAG_S not in request:  
30.         request += conn.recv(1024)  
31.   
32.     print("请求内容: ", request)  
33.     c = threading.current_thread()  
34.     _ = html_content.format(c.name)  
35.     resp_args.Append(_)  
36.     content_length = len(_.encode())  
37.     _resp = "rn".join(resp_args)  
38.   
39.     _resp = _resp.format(content_length)  
40.     conn.send(_resp.encode())  
41.     conn.close()  
42.   
43.   
44. def web_server():  
45.     # socket.AF_INET用于服务器与服务器之间同行  
46.     # socket.SOCK_STREAM用于基于TCP流的通信  
47.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
48.     server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  
49.     # 监听本地8888端口  
50.     server.bind(('127.0.0.1', 8888))  
51.     server.listen()  
52.     print("web server已经启动")  
53.   
54.     try:  
55.         n = 0  
56.         while True:  
57.             try:  
58.                 conn, address = server.accept()  
59.             except socket.error as e:  
60.                 if e.args[0] != errno.EAGAIN:  
61.                     raise Exception(e)  
62.                 continue  
63.   
64.             n += 1  
65.             # 通过threading实现web server多线程  
66.             t = threading.Thread(target=connet_operate, args=(conn, address), name='thread{}'.format(n))  
67.             t.start()  
68.     except Exception as e:  
69.         print(traceback.format_exc(e))  
70.         server.close()  
71.   
72. if __name__ == "__main__":  
73.     web_server()  

我们再访问该服务,其返回如下:

一文秒懂Web框架基础之WSGI协议

 

通过上述改造我们就实现了多线程的web服务器,了解了web服务的基本实现,下面我们就来看看WSGI的具体实现。

03 WSGI Application实现

在了解了基本的web服务的实现,我们看WSGI协议,WSGI协议分为两部分,一部分是web server或者网关就是上面web server代码一样,它监听在某个端口上接受外部的请求,另外一部分就是web应用,web server将接受到的请求数据通过WSGI协议规定的方式把数据传递给web应用,web应用处理完数据后设置对应的状态码与header然后返回,web server拿到返回数据之后再进行HTTP协议封装然后返回给客户端,下面我们看看WSGI协议通过代码的具体实现

1. #!/usr/bin/env/ python  
2. # -*- coding:utf-8 -*-  
3.   
4. import os  
5. import sys  
6.   
7.   
8. def _app(environ, response):  
9.     status = "200 OK"  
10.     resp_hearders = [('Content-Type', 'text/html')]  
11.     response(status, resp_hearders)  
12.     return [b'<h1>simple wsgi app</h1>n']  
13.   
14. def _to_bytes(content):  
15.     return content.encode()  
16.   
17. def run_with_cgi(application):  
18.     environ = dict(os.environ.items())  
19.     environ['wsgi.input'] = sys.stdin.buffer  
20.     environ['wsgi.errors'] = sys.stderr  
21.     environ['wsgi.version'] = (1, 0)  
22.     environ['wsgi.multithread'] = False  
23.     environ['wsgi.multiprocess'] = True  
24.     environ['wsgi.run_once'] = True  
25.   
26.     if environ.get('HTTPS', 'off') in ('on', '1'):  
27.         environ['wsgi.url_scheme'] = 'https'  
28.     else:  
29.         environ['wsgi.url_scheme'] = 'http'  
30.   
31.     headers_set = []  
32.     headers_sent = []  
33.   
34.     def write(data):  
35.         out = sys.stdout.buffer  
36.   
37.         if not headers_set:  
38.             raise ValueError("write before response()")  
39.   
40.         elif not headers_sent:  
41.             # 输出数据前, 先发送响应头  
42.             status, response_headers = headers_sent[:] = headers_set  
43.             out.write(_to_bytes('Status: {}rn'.format(status)))  
44.             for header in response_headers:  
45.                 out.write(_to_bytes('{}: {}rn'.format(header, header)))  
46.             out.write(_to_bytes('rn'))  
47.   
48.         out.write(data)  
49.         out.flush()  
50.   
51.     def response(status, response_headers, error_info=None):  
52.         if error_info:  
53.             try:  
54.                 if headers_sent:  
55.                     # 已经发送header就抛出异常  
56.                     raise (error_info[0], error_info[1], error_info[2])  
57.   
58.             finally:  
59.                 error_info = None  
60.   
61.         elif headers_set:  
62.             raise ValueError("Headers already set")  
63.   
64.         headers_set[:] = [status, response_headers]  
65.         return write  
66.   
67.     result = application(environ, response)  
68.   
69.     try:  
70.         for data in result:  
71.             # 没有body数据则不发送header  
72.             if data:  
73.                 write(data)  
74.         if not headers_sent:  
75.             write('')  
76.   
77.     finally:  
78.         if hasattr(result, 'close'):  
79.             result.clost()  
80.   
81. if __name__ == "__main__":  
82.     run_with_cgi(_app)  

现在我们运行编写的WSGI应用,具体如下:

一文秒懂Web框架基础之WSGI协议

 

通过执行该应用直接返回了状态信息、Header及body内容。上述代码就是Application在WSGI协议的实现。我们要实现Application只需要能够接收一个环境变量以及一个回调函数即可,如上面代码的“result = application(environ, response)”,在处理完请求通过回调函数respose来设置响应的状态和header,最后再返回body。在完成Application之后可以通过一些Web Server来调用,如Gunicorn Web server,限于篇幅限制就不详细讲解了,刚兴趣的朋友可以安装Gunicorn然后进行调用。

04 总结

至此我们WSGI协议就讲完了,如有什么问题欢迎在文章后面进行留言,最后如果喜欢本篇文章不要忘了点赞、关注与转发哦!



Tags:Web框架   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
TechEmpower BenchmarkTechEmpower 的测试比较科学,包含 SQL 查询、JSON 序列化等各种测试,同时标注了哪些是使用了 ORM,哪些是 RAW 查询。 TechEmpower Benchmark Web Framew...【详细内容】
2021-10-12  Tags: Web框架  点击:(70)  评论:(0)  加入收藏
这里测试的python异步框架几乎都与ASGI兼容(除了aiohttp)。基准测试的目的不是测试部署(例如uvicorn与hypercorn等)或数据库(ORM,驱动程序),而是测试框架本身。基准检查检查请求解...【详细内容】
2021-05-08  Tags: Web框架  点击:(266)  评论:(0)  加入收藏
本篇文章我们主要介绍WSGI协议,该协议用来描述Server与Framework之间的通信接口,我们日常使用的Python WEB框架Django、Flask、web.py等都遵循了该协议。下面我们就来详细了解...【详细内容】
2020-11-26  Tags: Web框架  点击:(130)  评论:(0)  加入收藏
Solon 是Java世界里一个新的极易上手的Web框架。参考过 Javalin 、 Spring 等很多现有框架的设计。取名自海贼王里的角色,说是希望能像他一样能打 小。真的是小。最小的运行...【详细内容】
2020-08-11  Tags: Web框架  点击:(92)  评论:(0)  加入收藏
今天我们来探索另外的一种框架的搭建,这个框架就是web框架-flask微框架啦!首先我们带着以下的几个问题来阅读本文:1、flask是什么?有些什么功能?2、搭建web框架-flask微框架需...【详细内容】
2019-12-13  Tags: Web框架  点击:(116)  评论:(0)  加入收藏
之前在Web开发框架推导一文中我们一步步的搭建了一个开发框架。 在当时的情况下,还算满足需求。但是随着项目的逐渐完善,需求变更的频度逐渐变得比新增需求的频度高,原来框架的...【详细内容】
2019-10-11  Tags: Web框架  点击:(126)  评论:(0)  加入收藏
Node.js是专注高性能服务器开发的javascript运行环境。我们将在这篇文章向大家介绍几款主流Node.js Web框架的特点及优缺点,希望给大家作为参考。主要参考的Node.js Web框架...【详细内容】
2019-08-29  Tags: Web框架  点击:(276)  评论:(0)  加入收藏
▌简易百科推荐
近日只是为了想尽办法为 Flask 实现 Swagger UI 文档功能,基本上要让 Flask 配合 Flasgger, 所以写了篇 Flask 应用集成 Swagger UI 。然而不断的 Google 过程中偶然间发现了...【详细内容】
2021-12-23  Python阿杰    Tags:FastAPI   点击:(6)  评论:(0)  加入收藏
文章目录1、Quartz1.1 引入依赖<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version></dependency>...【详细内容】
2021-12-22  java老人头    Tags:框架   点击:(11)  评论:(0)  加入收藏
今天来梳理下 Spring 的整体脉络啦,为后面的文章做个铺垫~后面几篇文章应该会讲讲这些内容啦 Spring AOP 插件 (了好久都忘了 ) 分享下 4ye 在项目中利用 AOP + MybatisPlus 对...【详细内容】
2021-12-07  Java4ye    Tags:Spring   点击:(14)  评论:(0)  加入收藏
&emsp;前面通过入门案例介绍,我们发现在SpringSecurity中如果我们没有使用自定义的登录界面,那么SpringSecurity会给我们提供一个系统登录界面。但真实项目中我们一般都会使用...【详细内容】
2021-12-06  波哥带你学Java    Tags:SpringSecurity   点击:(18)  评论:(0)  加入收藏
React 简介 React 基本使用<div id="test"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js...【详细内容】
2021-11-30  清闲的帆船先生    Tags:框架   点击:(19)  评论:(0)  加入收藏
流水线(Pipeline)是把一个重复的过程分解为若干个子过程,使每个子过程与其他子过程并行进行的技术。本文主要介绍了诞生于云原生时代的流水线框架 Argo。 什么是流水线?在计算机...【详细内容】
2021-11-30  叼着猫的鱼    Tags:框架   点击:(21)  评论:(0)  加入收藏
TKinterThinter 是标准的python包,你可以在linx,macos,windows上使用它,你不需要安装它,因为它是python自带的扩展包。 它采用TCL的控制接口,你可以非常方便地写出图形界面,如...【详细内容】
2021-11-30    梦回故里归来  Tags:框架   点击:(26)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  充满元气的java爱好者  博客园  Tags:SpringBoot   点击:(25)  评论:(0)  加入收藏
一、搭建环境1、创建数据库表和表结构create table account(id INT identity(1,1) primary key,name varchar(20),[money] DECIMAL2、创建maven的工程SSM,在pom.xml文件引入...【详细内容】
2021-11-11  AT小白在线中  搜狐号  Tags:开发框架   点击:(29)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  小程序建站    Tags:SpringBoot   点击:(55)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条