WSGI 概述和 APP 端开发| 学习笔记

简介: 快速学习 WSGI 概述和 APP 端开发

开发者学堂课程【Python Web 开发基础WSGI 概述和 APP 端开发】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/554/detail/7637


WSGI概述和APP端开发


内容简介:

一. WSGI 概述

二. WSGI 服务——wsgiref

三. WSGI 服务器作用

四. WSGI APP 应用程序端

五. environ

六. start_response


一. WSGI 概述

image.png


1、上图是 Python 的一种协议

即客户端的请求发送过来之后,Python 如何按照约定处理请求,处理之后把请求转换成数据,这些数据如何发送回浏览器端的流程图。

这张图可以分为两部分,第一部分是请求,一部分是 APP 。

这个协议要求两次返回。

两次返回的步骤如下:

首先,浏览器发起一个请求通过 Server,Server 本身是 TCP 的,在端口号等着,然后把这些请求做解析报文,解析完之后把数据封装成 environ,只解决 HTTP 协议,数据由 APP 处理。

处理好之后状态码和报文头由它自己去发送。实际上在这个协议中,在 Server 调用 APP 写的程序时,有两个参数进来,一个是 environ 解析的变量,另一个是 environ 发状态码和报文头的方法,即函数名。

函数是在 APP 处调用的,但是这个函数是 Server 提供的。返回的正文要被 Server 进行 HTTP 的封装,然后再返回给浏览器。

一个请求过来之后被解析,解析之后传入给 APP,其中传入两个参数,一个是 environ,另一个是写 HTTP  状态码、报文头给出的方法。一旦调用函数,报文头和状态码就返回去了,HTTP 正文会处理剩下的内容。这是协议本身的要求。

遵从这个协议建立的 Server 叫做 WSGI Server,遵从这个协议构建的 App 叫做 WSGI App。

总体来说,所有外部框架都是这样做的,浏览器发请求给 Server,Server再返回来,不管后面多少层,也不管后面调用多少次,给一个请求就有一个响应。 Server 主要就是 HTTP 解析和 HTTP 的报文封装。

APP 协议,最终就是函数套函数,或者调用类的方法,调用之后函数依次返回,最后正文封装返回过去。

2、WSGI 主要规定了服务器端和应用程序间的接口。

实际上 WSGI 解决了 Server 和 APP 之间的协议问题。Server 做与服务相关的事情,即客户端请求来了之后,建立一个连接,把数据传送过去。因为数据如何处理不是 Server 能决定的,应该由编程者来决定数据如何处理,数据处理之后应该得到什么样的结果返回回去。不能把这部分包含到 Server 里面,应该独立出去,所以 WSGI 解决的是 Server 与 APP 之间的接口问题。


二. WSGI 服务——wsgiref

1、wsgiref 这是一个 WSGl 参考实现库

wsgiref.simple_server 模块实现一个简单的 WSGI HTTP 服务器。

wsgiref.simple_server.make_server(host,port,app,server_class=WSGIServer,handler_class=WSGIRequestHandler) 启动一个 WSGI 服务器

wsgiref.simple_server .demo_app(environ,start_response) 一个函数,小巧完整的 WSGI 的应用程序的实现

2、返回文本例子

from wsgiref.simple_server import make_server,demo_app

ip = '127.0.0.1'

port = 9999

server = make_server(ip,port,demo_app)  # demo_app 应用程序,可调用

server.serve_forever()  # server.handle_request() 执行一次

3、范例:

From wsgiref.util import setup_testing_defaults

from wsgiref.simple_server import make_server

# A relatively simple WSGI application. It's going to print out the environment dictionary after being updated by setup_testing_defaults

def simple_app (environ, start_response):

setup_testing_defaults (environ)

status = '200 OK'

headers = [ ( 'Content-type',  'text/plain; charset=utf-8')]

start_response (status, headers)

ret = [ ( "%s : %s\n" % (key, value)) .encode ( "utf-8")

for key, value in environ.items()]

return ret  # 返回要求可迭代对象,正文就是这个列表的元素,可以是一个元素——字符串

httpd = make_server ( '0.0.0.0',8000, simple_app) #创建 server

print ( "Serving on port 8000...")

httpd.serve_forever()

1)点开 make_server 可以看到以下内容:

def make_server (host, port, app, server_class=WSGIServer,handler_class=WSGIRequestHandler) :

" ""Create a new WSGI server listening on 'host' and 'port’for 'app ' """

server = server_class ((host, port), handler_class)

server.set_app (app)

return server

2)这里是最简单的 APP,里面有两个参数。

Request Headers

GET /img/ bd_logo1.png HTTP/1.1

Host: www . baidu.com

Connection: keep-alive

Pragma: no-cache

把以上这些东西全部都封装到字典里面,然后就可以调用了。还要传一个参数: start_response,它是由 make_server (能够支持 HTTP 协议)。如果有请求来了,就调用 simple_app。

WSGIServer 是从 HTTPServer 来的,而 HTTPServer 是从 socket TCPServer 来的,但是要复杂一点,因为它里面要处理很多的数据,要进行 HTTP 的解析和封装。

from wsgiref.simple_server import make_server,demo_app

server = make_server ( ‘0.0.0.0', 9000,demo_app)

server.serve_forever ()

APP 也是有要求的,APP 必须能接受两个参数,APP 本身是一个可调用对象, APP 只能是函数类型的。

不管对服务器发起什么样的 HTTP 请求,都会用同一个函数去处理。

3)demo_app 里的内容如下:

def demo_app(environ, start_response) :

from io import stringIo

stdout = StringIo()

print ( "Hello world! ", file=stdout)

print (file=stdout)

h = sorted (environ. items () )

for k, v in h:

print (k,'=' , repr(v), file=stdout)

start_response ("200 oK",[( ' Content-Type ' , ' text/plain; charset=utf-8' )])

return [stdout.getvalue ().encode ( "utf-8"")]

demo_app 返回的内容放在一个内存中,关键把环境变量全部排序打印了。以上就是一个套路,我们要写的东西和它一样。

WSGI Server 内部是一个 TCP 的,但是它能够认得 HTTP 协议,可以做 HTTP 的解析和封装。它还能够把请求来到之后,调用写好的 APP。

Demo 为什么这样做,因为现在也不知道本地有什么文件,就用内存中的一个文件对象准备数据,准备好数据以后把这个字符串发出去即可,然后封装,通过 APP 返回浏览器端就可以了。

我们在那个基础上做,实际上不太关心最后怎么去读取环境变量,真正关心的是 HTTP 请求过来的东西被解析到字典,想看一下这个字典,代码如下:

def simple_app (environ, start_response):

print (environ)

status = '200 OK'

headers =[( 'Content-type', 'text/plain; charset=utf-8')]

start_response (status, headers)

ret = [( "%s: %s\n" %( key, value)) .encode ( "utf-8")

for key, value in environ.items () ]

return ret  # 返回要求可迭代对象,正文就是这个列表的元素,可以是一个元素——字符串

httpd = make_server ('0.0.0.0',9000, simple_app)  #创建 server

try:

httpd.serve_forever ()

except Exception as e:

print (e)

except KeyboardInterrupt:

print (' stop ' )

httpd.server_close()

4)注意:APP 这块要想办法要把里面的异常尽量捕获掉,而不是把异常抛给 WSGI Server,因为 WSGI Server 处理不了就会直接崩掉。如果能用 TCP server,那也是影响一个线程,关键在于怎么处理,如果一个请求扔给一个线程,那么最多那个请求所在线程崩掉。对于自己来写的 APP,异常处理是需要的,但是如果遇到一个框架,那个框架是在外面,包裹着把异常处理掉了。

捕获到网络只剩一个,因为只发起了一次 HTTP 请求,把环境数据准备好,然后都打印出来,之后把这些数据是又作为响应的报文传回来了。

5)Request Headers

GET / HTTP/1.1

Host: 127.8.e.1:9000

Connection: keep-alive

Pragma: no-cache

Cache-Control: no-cache

Upgrade-Insecure-Requests: 1

X-DevTools-Emulate-Network-Conditions-client-Id: 9f2371c6-1a96-42c4-a081-a90705ded03f

User-Agent : Mozilla/5.0 (Windows NT 6.1; WOW64) ApplewebKit/537.36 (KHTML,like Gecko) Maxthon/5.1.0.4.0000 Chrome/55.0.2883.75 Safari/537.36

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,* /*; q=0.8

请求依然是 get,对根发起了访问,然后允许长段时间连接,尽量保持连接。都是浏览器发的,浏览器在跟 server 之间做协商。不管怎么样,HTTP 协议都是支持文本的,所以没返回 html,返回的是纯文本。

响应了一些内容:

HTTP/1.1 200 OK

Date: Mon,25 Jun 2018 06:40:22 GMT

Server: WSGIServer/0.2 CPython/ 3.5.3

Content-type: text/plain; charset=utf-8

Transfer-Encoding: chunked

即发回来纯文本,不是 html,是 utf-8 编码的。

6)environ

environ 是包含 Http 请求信息的 dict 对象

名称及含义如下:

REQUEST_METHOD :请求方法,GET、POST 等

PATH_INFO :URL 中的路径部分

QUERY_STRING :查询字符串

SERVER_NAME, SERVER_PORT :服务器名、端口

HTTP_HOST :地址和端口

SERVER_PROTOCOL :协议

HTTP_USER_AGENT :UserAgent 信息

请求头的字典在客户端打印出来,其中 REMOTE ADDR127.0.0.1 远程地址还是要关心的,即浏览器是用什么 IP 地址来访问的。主要关心 environment 里面的比如 pass,method 这些信息。


三. WSGI 服务器作用


1)监听 HTTP 服务端口 (TCPServer,默认端口80 )

2)接收浏览器端的 HTTP 请求并解析封装成 environ 环境数据

3)负责调用应用程序,将 environ 和 start_response 方法传入

4)将应用程序响应的正文封装成 HTTP 响应报文返回浏览器端


四. WSGI APP 应用程序端

1、应用程序应该是一个可调用对象

Python 中应该是函数、类、实现了 _call_ 方法的类的实例

class A:

def _init_(self, name, age):

pass

def _call_(self, environ, start_response) :

pass

class B:

def _init_(self, environ, start_response):

for k, v in environ.items ():

print (k, v)

print ('-‘ *30)

status ='200 OK‘

headers = [ ( 'Content-type', 'text/plain; charset=utf-8')]

start_response (status, headers)

ret =[("%s : %s\n" %(key, value) ) .encode ( "utf-8")

for key, value in environ.items()]

self.ret = ret

return ret  # 返回要求可迭代对象,正文就是这个列表的元素,可以是一个元素——字符串

def _iter_(self):

yield from self.ret

2、这个可调用对象应该接收两个参数

#1函数实现

def application(environ, start_response):

pass

#2类实现

class Application:

def _init_(self, environ, start_response):

pass

#3类实现

class Application:

def _cal1_(self, environ, start_response):

pass

3、以上的可调用对象实现,都必须返回一个可迭代对象

res_str = b 'magedu.com\n '

#函数实现

def application(environ, start_response):

return [res_str]

#类实现

class Application:

def _init_(self, environ, start_response):

pass

def _iter_(se1f):  # 实现此方法,对象即可迭代公

yield res_str

#类实现

class Application:

def _call_(self, environ, start_response):

return [res_str]

environ和start_response这两个参数名可以是任何合法名,但是一般默认都是这2个名字。应用程序端还有些其他的规定,暂不用关心。

for x in B (environ, start response):

for x in simple_app(environ, start response) :

xyz(x)

对比这两行,初始化函数传参进去之后,返回的对象要可迭代,返回不能直接 return。


五. environ


environ 是包含 Http 请求信息的 dict 对象

名称及含义如下:

REQUEST_METHOD :请求方法,GET、POST 等

PATH_INFO :URL 中的路径部分

QUERY_STRING :查询字符串

SERVER_NAME, SERVER_PORT :服务器名、端口

HTTP_HOST :地址和端口

SERVER_PROTOCOL :协议

HTTP_USER_AGENT :UserAgent 信息

其中比较重要的是 PATH_INFO,QUERY_STRING  和HTTP_USER_AGENT。

UserAgent 一般是用来做分析的,其实请求到底是 A 浏览器还是 B 浏览器,一般情况下不太关心,但是有的时候要关心。因为用户如果是 IE 的,实际上支持的 html 和 CSS 的版本是不一样的。如果返回的东西是统一的回去的话,最后会发现可能在某一个浏览器里面错位了,整个 html 就变形了。所以用户体验会非常糟糕,就会选择关闭。

所以 UserAgent 最早是解决,浏览器端告诉是什么软件,用户必须按照浏览器支持的版本,至于到底兼容不兼容正在使用浏览器,那是你的问题。但是现在在客户端也是用各种框架,其实用框架来解决不同浏览器之间的兼容性问题,所以现在可以写个统一的页面。但是如果特别在意用户这边的显示的话,实际上还是要让你去看一下用户的 UserAgent 究竟是什么,然后给他配相应的 html 回去,不然不支持。


六. start_response


它是一个可调用对象。有3个参数,定义如下∶

start_response(status, response_headers, exc_info=None) status 是状态码,例如200 OK

response_headers 是一个元素为二元组的列表,例如 [('Content-Type', 'text/plain; charset=utf-8')]  

exc_info 在错误处理的时候使用

start_response 应该在返回可迭代对象之前调用,因为它返回的是 Response Header。返回的可迭代对象是  Response Body。

相关文章
|
15天前
|
缓存 移动开发 JavaScript
如何优化UniApp开发的App的启动速度?
如何优化UniApp开发的App的启动速度?
270 139
|
15天前
|
移动开发 JavaScript weex
UniApp开发的App在启动速度方面有哪些优势和劣势?
UniApp开发的App在启动速度方面有哪些优势和劣势?
213 137
|
1月前
|
移动开发 小程序 Android开发
基于 uni-app 开发的废品回收类多端应用功能与界面说明
本文将对一款基于 uni-app 开发的废品回收类多端应用,从多端支持范围、核心功能模块及部分界面展示进行客观说明,相关资源信息也将一并呈现。
82 0
|
8天前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
79 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
15天前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
185 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
3月前
|
人工智能 文字识别 小程序
旅游社用什么工具收报名 + 资料?不开发 App 也能自动收集信息
本文探讨了旅游行业中报名信息收集的常见痛点及解决方案,重点介绍了二维码表单工具在提升信息收集效率、简化操作流程方面的优势。通过对比多种工具,分析其适用场景与实际应用逻辑,为一线旅游从业者提供高效、低成本的执行参考。
|
16天前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
258 3
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
4月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:外卖App
仓颉语言实战分享,教你如何用仓颉开发外卖App界面。内容包括页面布局、导航栏自定义、搜索框实现、列表模块构建等,附完整代码示例。轻松掌握Scroll、List等组件使用技巧,提升HarmonyOS应用开发能力。
|
3月前
|
Rust 安全 前端开发
Github 轻松斩获30k+ Star,桌面应用开发太丝滑啦,Tauri框架能重塑桌面App开发?别错过,抓紧上车
Tauri 是一个基于 Rust 的开源框架,用于构建轻量级、高性能、安全的跨平台桌面及移动应用。它利用系统 WebView 渲染前端界面,后端由 Rust 编写,具备出色的性能和安全性。相比 Electron,Tauri 应用体积更小、启动更快,且默认权限更安全。它支持 React、Vue、Svelte 等主流前端框架,并提供自动更新、CLI 工具链、资源注入优化等功能,适用于生产力工具、开发者工具、数据分析、AI 应用等多种场景。目前 Tauri 在 GitHub 上已获得超过 30,000 Star,社区活跃,是现代桌面应用开发的理想选择。
292 0

热门文章

最新文章