Python学习教程:WEB开发——Python WSGI协议详解

Web应用程序开发

Web应用程序的本质是什么

简单描述Web应用程序的本质,就是我们通过浏览器访问互联网上指定的网页文件展示到浏览器上。

流程如下图:

从更深层次一点的技术角度来看,由以下几个步骤:

  • 浏览器,将要请求的内容按照HTTP协议发送服务端
  • 服务端,根据请求内容找到指定的HTML页面
  • 浏览器,解析请求到的HTML内容展示出来

HTTP协议的全称是HyperText Transfer Protocol(超文本传输协议)

HTTP协议是我们常用的五层协议中的应用层(5层从上到下是应用层,传输层,网络层,数据链路层,物理层),HTTP协议中协定的内容称之为消息,消息主要包括消息头——Header和消息体——Body。

客户端请求时的消息称为Request,服务端响应时的消息称为Response.

Header:包括请求方法,HTTP版本,URI,状态码,COOKIE等

Body:是响应或者请求时的内容,包含HTML,CSS,JS等

HTTP协议这里就不做过多的描述,可以到点击这里深入了解HTTP协议

HTML的全称是Hyper Text Markup Language(超文本标记语言)

简单点说,HTML 是一种由不同元素组成的标记语言,它定义了网页内容的含义和结构,所有我们在浏览器中看到的内容都是由一个一个的元素组成。除 HTML 以外的其它技术则通常用来描述一个网页的表现与展示效果(如 CSS),或功能与行为(如 JavaScript)。

WEB开发的历程

静态开发

直接将写好的HTML页面放在服务器上,然后直接通过浏览器访问指定服务器的文件。

动态开发

随着我们的需求变化单独使用静态开发已经不能完全满足我们。例如我们查看的页面只有部分内容会变化,那我们再去开发相同的页面。一是开发上是一种重复工作,完全是一种浪费。二是数据量变化巨大时,完全是跟不上速度,并且数据变化也不是定时更新。为了应对这种问题,动态网页技术也就诞生了。早期的动态网页开发技术是CGICGI全称:Common Gateway Interface,通用网关接口,它是一段程序,运行在服务器上如:HTTP 服务器,提供同客户端 HTML 页面的接口。CGI 程序可以是 Python 脚本,PERL 脚本,SHELL 脚本,C 或者 C++ 程序等。各种编程语言也针对动态网页开发给出不同的解决方案,JAVA的servlet,Python的WSGI协议等。

Python的WSGI协议也是我们本章要讲的内容

CGI流程

WSGI的流程

什么是WSGI

WSGI全称是Web Server Gateway Interface,其主要作用是Web服务器与Python Web应用程序或框架之间的建议标准接口,以促进跨各种Web服务器的Web应用程序可移植性。

WSGI并不是框架而只是一种协议,我们可以将WSGI协议分成三个组件Application,Server,Middleware和协议中传输的内容。

将这三个组件对映射到我们具体使用的组件是:

Server:常用的有uWSGI,gunicorn等

Application:Django,Flask等

Middleware: Flask等框架中的装饰器

点击这里查看官方关于WSGI协议的定义

组件Application

应用程序,是一个可重复调用的可调用对象,在Python中可以是一个函数,也可以是一个类,如果是类的话要实现__call__方法,要求这个可调用对象接收2个参数,返回一个内容结果

接收的2个参数分别是environ和start_response。

  • environ是web服务器解析HTTP协议的一些信息,例如请求方法,请求URI等信息构成的一个Dict对象。
  • start_response是一个函数,接收2个参数,一个是HTTP状态码,一个HTTP消息中的响应头。

依照官方提供的示例用函数实现应用程序

def simple_app(environ, start_response): """Simplest possible application object""" status = ‘200 OK‘ response_headers = [(‘Content-type‘, ‘text/plain; charset=utf-8‘)] start_response(status, response_headers)

 return_body = []

 for key, value in environ.items(): return_body.append("{} : {}".format(key, value))

 return_body.append("\nHello WSGI!") # 返回结果必须是bytes return ["\n".join(return_body).encode("utf-8")]

组件Server

Web服务器,主要是实现相应的信息转换,将网络请求中的信息,按照HTTP协议将内容拿出,同时按照WSGI协议组装成新的数据,同时将提供的start_response传递给Application。最后接收Application返回的内容,按照WSGI协议解析出。最终按照HTTP协议组织好内容返回就完成了一次请求。

Server操作的步骤如下:

  1. 根据HTTP协议内容构建envrion
  2. 提供一个start_response函数,接收HTTP STATU 和 HTTP HEADER
  3. 将envrion和start_response作为参数调用Application
  4. 接收Application返回的结果
  5. 按照HTTP协议,顺序写入HTTP响应头(start_response接收),HTTP响应体(Application返回结果)

下面这个是pep3333协议中的一个server例子,按照CGI请求的方式来实现。

import os, sysenc, esc = sys.getfilesystemencoding(), ‘surrogateescape‘def unicode_to_wsgi(u): # Convert an environment variable to a WSGI "bytes-as-unicode" string return u.encode(enc, esc).decode(‘iso-8859-1‘)def wsgi_to_bytes(s): return s.encode(‘iso-8859-1‘)def run_with_cgi(application):	# 按照WSGI协议,构建environ内容	# 1类 CGI相关的变量,此脚本就是用于cgi执行,所以前面的web服务器已经将CGI变量封装好,这里直接使用 environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()} # 2类 wsgi定义的变量 environ[‘wsgi.input‘] = sys.stdin.buffer environ[‘wsgi.errors‘] = sys.stderr environ[‘wsgi.version‘] = (1, 0) environ[‘wsgi.multithread‘] = False environ[‘wsgi.multiprocess‘] = True environ[‘wsgi.run_once‘] = True if environ.get(‘HTTPS‘, ‘off‘) in (‘on‘, ‘1‘): environ[‘wsgi.url_scheme‘] = ‘https‘ else: environ[‘wsgi.url_scheme‘] = ‘http‘ headers_set = [] headers_sent = [] def write(data):	 # 将内容返回 out = sys.stdout.buffer if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set out.write(wsgi_to_bytes(‘Status: %s\r\n‘ % status)) for header in response_headers: out.write(wsgi_to_bytes(‘%s: %s\r\n‘ % header)) out.write(wsgi_to_bytes(‘\r\n‘)) out.write(data) out.flush()

 def start_response(status, response_headers, exc_info=None): if exc_info: try: if headers_sent: # Re-raise original exception if headers sent raise exc_info[1].with_traceback(exc_info[2]) finally: exc_info = None # avoid dangling circular ref elif headers_set: raise AssertionError("Headers already set!") headers_set[:] = [status, response_headers] # Note: error checking on the headers should happen here, # *after* the headers are set. That way, if an error # occurs, start_response can only be re-called with # exc_info set. return write

	# 将上面处理的参数交给应用程序 result = application(environ, start_response) try:	 # 将请求到的结果写回。 for data in result: if data: # don‘t send headers until body appears write(data) if not headers_sent: write(‘‘) # send headers now if body was empty finally: if hasattr(result, ‘close‘): result.close()

组件Middleware

中间件,可以理解为对应用程序的一组装饰器。

在应用程序端看来,它可以提供一个类start_response函数,可以想start_response函数一样接收HTTP STATU和Headers;和environ。

在服务端看来,他可以接收2个参数,并且可以返回一个类Application对象。

下面看一个例子,记录每次请求的消耗时间:

import timeclass ResponseTimingMiddleware(object): """记录请求耗时""" def __init__(self, app): self.app = app def __call__(self, environ, start_response): start_time = time.time() response = self.app(environ, start_response) response_time = (time.time() - start_time) * 1000 timing_text = "记录请求耗时中间件输出\n\n本次请求耗时: {:.10f}ms \n\n\n".format(response_time) response.append(timing_text.encode(‘utf-8‘)) return response

协议内容

重点看environ有哪些内容,这里面才是浏览器每次请求时的信息。再深入一点探索,就是HTTP请求消息中的请求头和请求体都是怎么定义及怎么回去的。

environ是一个字典,environ中要包含CGI定义的变量,主要是将HTTP协议中的内容,比如请求方法,POST/GET,请求URI等,另外是WSGI协议自己定义的变量,比如请求body中要读取的信息等。列一下主要变量项如下:

CGI相关变量

变量说明REQUEST_METHODPOST,GET等,HTTP请求的动词标识SERVER_PROTOCOL服务器运行的HTTP协议. 这里当是HTTP/1.0.PATH_INFO附加的路径信息, 由浏览器发出.QUERY_STRING请求URL的“?”后面的部分CONTENT_TYPEHTTP请求中任何Content-Type字段的内容CONTENT_LENGTH标准输入口的字节数.HTTP_[变量]其他一些变量,例如HTTP_ACCEPT,HTTP_REFERER等

上述内容是动态开发的根基,只有根据上述内容才可以标准化的动态处理请求。

WSGI定义变量

变量说明wsgi.versionWSGI版本,要求是元组(1,0),标识WSGI 1.0协议wsgi.url_scheme表示调用应用程序的URL的协议,http或httpswsgi.input类文件对象,读取HTTP请求体字节的输入流wsgi.errors类文件对象,写入错误输出的输出流wsgi.multithread如果是多线程,则设置为True,否则为False。wsgi.multiprocess如果是多进程,则设置为True,否则为False。wsgi.run_once如果只需要运行一次,设置为True

WSGI协议对于两个输入输出流有一些方法必须要实现

流方法wsgi.inputread(size)wsgi.inputreadline()wsgi.inputreadlines(hint)wsgi.inputiter()wsgi.errorsflush()wsgi.errorswrite(str)wsgi.errorswritelines(seq)

这些基本上就是WSGI协议中定义的主要变量,也基本上涵盖了我们开发时所需要的变量。

Server端按照协议的内容生成这些environ字典,然后将请求信息交给Application,Application根据这些信息确认请求要处理的内容,然后返回响应消息。从头顺下来就是这个流程。

示例展示

Server端涉及到实现http相关内容,我们直接使用python内置wsgiref来实现,具体代码如下:

import timefrom wsgiref.simple_server import make_serverclass ResponseTimingMiddleware(object): """记录请求耗时""" def __init__(self, app): self.app = app def __call__(self, environ, start_response): start_time = time.time() response = self.app(environ, start_response) response_time = (time.time() - start_time) * 1000 timing_text = "记录请求耗时中间件输出\n\n本次请求耗时: {:.10f}ms \n\n\n".format(response_time) response.append(timing_text.encode(‘utf-8‘)) return responsedef simple_app(environ, start_response): """Simplest possible application object""" status = ‘200 OK‘ response_headers = [(‘Content-type‘, ‘text/plain; charset=utf-8‘)] start_response(status, response_headers)

 return_body = []

 for key, value in environ.items(): return_body.append("{} : {}".format(key, value))

 return_body.append("\nHello WSGI!") # 返回结果必须是bytes return ["\n".join(return_body).encode("utf-8")]# 创建应用程序app = ResponseTimingMiddleware(simple_app)# 启动服务,监听8080httpd = make_server(‘localhost‘, 8080, app) httpd.serve_forever()

启动服务后,我们打开浏览器访问http://localhost:8080,执行结果如下。

上图可以看到我们前面提到的中间件以及Application中执行返回的结果全都实现。

Python学习教程关于WSGI协议内容就到这,可以说是非常良心,非常详细了!大伙儿,用心学哈!

原文地址:https://www.cnblogs.com/cherry-tang/p/11251966.html

时间: 2025-01-09 06:46:09

Python学习教程:WEB开发——Python WSGI协议详解的相关文章

Python学习教程(Python学习路线):Pandas库基础分析-详解时间序列的处理

Python学习教程(Python学习路线):Pandas库基础分析-详解时间序列的处理 在使用Python进行数据分析时,经常会遇到时间日期格式处理和转换,特别是分析和挖掘与时间相关的数据,比如量化交易就是从历史数据中寻找股价的变化规律.Python中自带的处理时间的模块有datetime,NumPy库也提供了相应的方法,Pandas作为Python环境下的数据分析库,更是提供了强大的日期数据处理的功能,是处理时间序列的利器. 1.生成日期序列 主要提供pd.data_range()和pd.p

《Linux高性能服务器编程》学习总结(二)——IP协议详解

第二章      IP协议详解 IP协议是TCP/IP协议族中的核心协议,也是socket网络编程的基础之一.IP协议的特点是为上层提供无状态.无连接.不可靠的服务. 无状态是指IP通信双方不同步传输数据的状态信息,通俗一些说就是双方发送的IP数据报是相互独立的,没有任何上下文关系.这样的特性缺点在于无法处理重复和乱序的IP数据报,举个例子,假设由于网络原因或者IP选路的原因导致第N个数据报比第N+1个数据报晚到达目的主机或同一个IP数据报经过不同的路径多次到达目的端,此时接收端的IP模块无法检

python基础教程笔记——画幅好画(详解)

今天写一下基础教程里面的第二个项目,主要使用python来做一个pdf的图,比较简单. 首先我们需要安装用到的模块pip install reportlab即可. 书上是用urlopen从往上下了一个txt文件,然后打开处理一下得到数据,因为我从这个url路径没有获取到数据,所以直接写了一点数据在程序里. urlopen比较简单,以后写爬虫也会经常用到,所以这里就不讲了,只单独讲讲reportlab模块. #encoding:utf8 from reportlab.graphics.shapes

Python学习之属性访问与描述符详解

在Python开发中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象 foo ,它有一个 name 属性,那便可以使用 foo.name 对此属性进行访问.一般而言,点(.)属性运算符比较直观,也是我们经常碰到的一种属性访问方式.然而,在点(.)属性运算符的背后却是别有洞天,值得我们对对象的属性访问进行探讨. 在进行对象属性访问的分析之前,我们需要先了解一下对象怎么表示其属性.为了便于说明,本文以新式类为例.有关新式类和旧式类的区别,大家可以查看Pyt

linux架构学习第二十五天HTTP协议详解

内容: 1.http协议概述 2.http协议特点 3.http的工作模式(过程) 4.http请求报文.响应报文格式.常见状态码解析 5.web资源概述(静态资源.动态资源) 1.http协议概述 http协议工作在TCP/IP模型的应用层,其定义web服务间通信的约定通信方式,HTTP基于tcp传送数据,默认是80端口(服务器端) 几个名词: http:hyper text transfer protocol,超文本传输协议,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(

Java Web开发 SSH配置文件案例详解(eclipse开发自存)

本文并没有具体的Dao,Service,Action代码实现,知识分享了下SSH整合框架中 那些配置文件的模板,仅供参考,有不对的地方欢迎大家指正 简单实例:实体类Departmentinfo 与 Employeeinfo 如下 package com.prj.bean; import java.util.HashSet; import java.util.Set; /** * Departmentinfo entity. @author MyEclipse Persistence Tools

Python学习教程:人生苦短,我用Python?入门前你要知道这些

有多少伙伴是因为一句 ‘人生苦短,我用Python’就要去学Python的? 之前也大家更新过Python学习教程普及过多次的Python相关知识,不过大家还是还得计划一下Python学习路线!Python入门前,一定要知道这些,你只有了解它,才能深入它! python是什么?  编程开发语言有很多种,通常大家把开发语言划分为静态编译和动态解析语言,静态编译语言有我们常见的c,c++等,动态解析语言有我们常见的python,php等.静态编译语言其中一个明显的特征是:需要对源代码进行编译成可执行

python学习之web中的html

Web概述web起源web特点1.易导航和图形化界面2.与平台无关3.分布式结构4.动态性5.交互性 html 网页结构 HTML(Hyper Text Mark-up Language )即是超文本标记语言, 通过使用标记标签来描述页面文档结构和表现形式的一种语言,再由浏览器进行解析,然后把结果展示在网页上.?超文本指的是超链接?标记指的是标签1).HTML文件用编辑器打开显示的是文本,可以用文 本的方式编辑.2). HTML文件用浏览器打开,浏览器会按照标签描述内容将文件渲染成网页,显示的网

2019最新Python学习教程(Python学习路线_Python爬虫教程)爬虫工程师必备的10个爬虫工具

2019最新Python学习教程(Python学习路线_Python爬虫教程)爬虫工程师必备的10个爬虫工具 爬虫工程师必备的10个爬虫工具! 最近很多学爬虫的伙伴让推荐顺手的爬虫工具,总结了一下,把这些好用的爬虫工具都跟你们找齐活了! 磨刀不误砍柴工!都知道工欲善其事必先利其器,那么作为经常要和各大网站做拉锯战的爬虫工程师们,更需要利用利用好身边的一切法器,才能更快的攻破对方防线.这里以日常爬虫流程,给大家介绍十款爬虫工具,相信大家掌握以后,工作效率提高是完全没有问题了! 大家也可以看看有你们