Werkzeug

Werkzeug

模块结构图大致如下(并没有完全列出模块所有内容)

首先我们来回忆一下WSGI协议的内容

  1. 我们需要实现一个apllication的函数或者类,然后传入envrion环境变量和start_response函数,返回一个可迭代的二进制流对象

  2. 我们需要实现一个遵循WSGI规范的服务器

整体代码如下:

from wsgiref.simple_server import *

def application(environ,start_response):
    start_response('200 OK',[('content-type','text/html')])
    return [b'

hello

'
] server = make_server('127.0.0.1',8888,application) server.serve_forever()

现在我们来看一下wrappers模块中的内容

这个模块主要包含了两个类:BaseRequest,BaseResponse外加多个MIXIN


BaseRequest(environ) 类 ,请求对象类

这个类通过传入环境参数来读取浏览器的请求内容,是只读的.

  • 使用@Request.application装饰器,此装饰器是将一个函数装饰为application

    传入装饰器的是environstart_response,但是传入application的是包装后的Request对象

@Request.application
def application(request):
    return Response('

hello

'
, status='200 OK', content_type='text/html')
  • environ WSGI环境参数

  • args 解析url的参数,使用get方法时,采用此属性获取键值

编写index网页


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>titletitle>
head>
<body>
    <h1>这是一个index网页h1>
    <form action="/form" method="get">
        <p><input type="text" name="name">p>
        <p><input type="text" name="age">p>
        <p><input type="submit">p>
    form>
body>
html>

编写form网页,使用jinja2模板


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    <h1>这是一个form网页h1>
    <h2>name : {{ name }} h2>
    <h2>age:  {{ age }} h2>
body>
html>

编写application

from werkzeug.wrappers import *
from werkzeug.routing import *
from wsgiref.simple_server import *
from jinja2 import *

@Request.application
def application(request):
    url_path = request.path
    if url_path == '/':
        data = open('index.html','rb').read()
        return Response(data, status='200 OK', content_type='text/html')
    if url_path == '/form':
        name = request.args['name']
        age = request.args['age']
        data = open('form.html','r',encoding='utf-8').read()
        return Response(Template(data).render(name=name,age=age), status='200 OK', content_type='text/html')

server = make_server('127.0.0.1', 8888, application)
server.serve_forever()
  • base_url 原始url,不含参数

  • cookies cookie内容

  • data 请求体中的内容

  • files 上传的文件对象,返回MultiDict对象,选择文件后返回FileStorage对象

我们现在实现一个上传文件的例子

index.html网页中的内容


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>titletitle>
head>
<body>
    <h1>这是一个index网页h1>
    <form action="/file" method="post" enctype="multipart/form-data">
        <p><input type="file" name="name">p>
        <p><input type="submit">p>
    form>
body>
html>

application中的内容

from werkzeug.wrappers import *
from werkzeug.routing import *
from wsgiref.simple_server import *
from jinja2 import *

@Request.application
def application(request):
    url_path = request.path
    response = Response(status='200 OK',content_type='text/html')
    if url_path == '/':
        data = open('index.html','r',encoding='utf-8').read()
        response.data = data
        return response
    if url_path == '/file':
        file = request.files.get('name')
        file.save(file.filename)
        response.data = ('%s文件已被上传'%file.filename).encode()
        return response

server = make_server('127.0.0.1', 8888, application)
server.serve_forever()
  • form 表单,使用post方法时,采用此属性获取键值

接着args中的例子,我们将index中form的method方法改为POST

这时,我们就需要采用form属性来获取值了

代码如下:

from werkzeug.wrappers import *
from werkzeug.routing import *
from wsgiref.simple_server import *
from jinja2 import *

@Request.application
def application(request):
    url_path = request.path
    if url_path == '/':
        data = open('index.html','rb').read()
        return Response(data, status='200 OK', content_type='text/html')
    if url_path == '/form':
        name = request.form['name']
        age = request.form['age']
        data = open('form.html','r',encoding='utf-8').read()
        return Response(Template(data).render(name=name,age=age), status='200 OK', content_type='text/html')

server = make_server('127.0.0.1', 8888, application)
server.serve_forever()
  • headers 请求头文件

  • host 主机地址

  • method 请求方法

  • path 请求路径,不含base_url


BaseResponse(response = None,status = None,headers = None,mimetype = None,content_type = None,direct_passthrough = False ) 响应类

构造一个响应对象,可进行写入操作

  • status 响应代码及消息

  • headers 响应头文件

  • data 响应内容,可以向其写入二进制内容,最好使用set_data()get_data()

  • get_app_iter(environ) 返回环境的迭代器

  • set_cookie(key,value ='',max_age = None,expires = None,path ='/',domain = None,secure = False,httponly = False,samesite = None ) 设置cookie

  • set_data(value) 设置响应内容

  • get_data() 获取响应内容

构造一个响应对象,可以使用构造函数进行构造,也可以使用属性,函数进行赋值

response = Response('

Hello

', status='200 OK')
response.set_data(xxxxx) response.set_cookie(xxxx)

MIXIN 用于扩展BaseResponseBaseRequest的功能

  • Reuquest MIXIN

    AcceptMixin 用于接受头解析
    ETagRequestMixin 用于etag和缓存控制处理
    UserAgentMixin 用于用户代理内省
    AuthorizationMixin 用于http身份验证处理
    CommonRequestDescriptorsMixin 用于常见标题

  • Response MIXIN

    ETagResponseMixin 用于etag和缓存控制处理
    ResponseStreamMixin添加对流属性的支持
    CommonResponseDescriptorsMixin 用于各种HTTP描述符
    WWWAuthenticateMixin 用于HTTP身份验证支持


datastructures模块中的内容

该模块主要为几种常用的结构

MultiDict(mapping) 类 是一个字典的子类,主要用来解析html表单

  • 可以使用[]或者get访问值
  • add(键,值) 添加新键值对
  • clear() 删除所有数据
  • get(键,默认=无,类型=无) 返回值
  • getlist(键,类型=无) 返回key的列表
  • iteritems(multi = False ) 返回key,value迭代器
  • pop(键,默认=无值) 删除键值

Headers (dict) 有序的字典,用来存储标头

  • add(_key,_value,** kw ) 添加新标头元组
  • clear() 删除所有数据
  • extend(dict) 使用字典扩展标头
  • get(key,default = None,type = None,as_bytes = False ) 获取值
  • getlist(key,type = None,as_bytes = False ) 返回字段值的所有列表

FileStorage(stream = None,filename = None,name = None,content_type = None,content_length = None,headers = None ) 类 表示上传的文件

  • filename 文件的名称
  • save(dst,buffer_size = 16384 ) 保存文件

routing 模块 URL路由

URL路由 : 主要是用来将URL地址与网页文件的实际路径联系在一起,也就是将URL中的地址映射到服务器上相应的处理函数中

@Request.application
def application(request):
    url_path = request.path
    if url_path == XXX:
        return Response1
    if url_path == XXX:
        return Response2

从上面的例子我们已经可以看出,如果浏览器访问不同的网页,那么服务器就要对这些不同的网页每个都对应一个处理的函数,当网页总数少的时候,可以很简单的编写,但是当网页总量大的时候,就只是编写相应的处理函数都十分庞大,就算完成了代码,那么维护的代价十分庞大

这个时候就是URL路由出场的时候了,URL路由能将不同的URL绑定到相应的处理函数上

Rule(string,defaults = None,subdomain = None,methods = None,build_only = False,endpoint = None,strict_slashes = None,redirect_to = None,alias = False,host = None )

该类构造一个Rule规则对象,此对象主要是创建URL规则

endpoint 指向一个对象,映射具有两种方式,一种是直接映射到函数,另一种通过字典映射到相应函数

直接映射到函数

from werkzeug.wrappers import *
from werkzeug.routing import *
from wsgiref.simple_server import *

def on_index():
    return Response('

index

'
, status='200 OK', content_type='text/html') url_map = Map([ Rule('/',endpoint=on_index()) ]) @Request.application def application(request): adapter = url_map.bind_to_environ(request.environ) endpoint, args = adapter.match() return endpoint server = make_server('127.0.0.1', 8888, application) server.serve_forever()

通过字典映射到函数

from werkzeug.wrappers import *
from werkzeug.routing import *
from wsgiref.simple_server import *

def on_index():
    return Response('

index

'
, status='200 OK', content_type='text/html') url_map = Map([ Rule('/',endpoint='index') ]) views = {'index':on_index()} @Request.application def application(request): adapter = url_map.bind_to_environ(request.environ) endpoint, args = adapter.match() return views[endpoint] server = make_server('127.0.0.1', 8888, application) server.serve_forever()

提到Rule就得提到内置转换器,内置转换器就是将URL格式化,只要是按照相应格式的URL就能被MapAdapter对象识别,进而映射到相应的处理函数中

内置转换器

  • UnicodeConverter(map,minlength = 1,maxlength = None,length = None ) 接收任何字符串,只能接收一个路径段,不能包含’/’

    用法 :

  • PathConverter(map ) 和UnicodeConverter相似,但可以接受多个路径段

    用法 :

  • AnyConverter(map,* items ) 匹配任意一个参数

    用法 :

  • IntegerConverter(map,fixed_digits = 0,min = None,max = None ) 接收一个整形数字

    用法 :

  • FloatConverter(map,min = None,max = None ) 接收一个浮点数

    用法 :

  • UUIDConverter(map ) 仅接受UUID字符串

    用法 :

使用内置转换器构造规则集合,可以使用已经定义的几种规则访问网页了

from werkzeug.wrappers import *
from werkzeug.routing import *
from wsgiref.simple_server import *

def on_index(request):
    return Response('

访问的地址是index,调用的函数是on_index

'
.encode(),status='200 OK', content_type='text/html; charset=utf-8') def on_num(request): return Response('

访问的地址是:{0},调用的函数是: on_num

'
.format(request.path),status='200 OK', content_type='text/html; charset=utf-8') def on_str(request): return Response('

访问的地址是:{0},调用的函数是: on_str

'
.format(request.path),status='200 OK', content_type='text/html; charset=utf-8') def on_any(request): return Response('

访问的地址是:{0},调用的函数是: on_any

'
.format(request.path),status='200 OK', content_type='text/html; charset=utf-8') url_map = Map([ Rule('/', endpoint=on_index), Rule('/',endpoint=on_any), Rule('/', endpoint=on_num), Rule('///', endpoint=on_num), Rule('//', endpoint=on_num), Rule('/', endpoint=on_str) ]) @Request.application def application(request): adapter = url_map.bind_to_environ(request.environ) endpoint, args = adapter.match() return endpoint(request) server = make_server('127.0.0.1', 8888, application) server.serve_forever()

Map(rules = None,default_subdomain ='',charset ='utf-8',strict_slashes = True,redirect_defaults = True,converter = None,sort_parameters = False,sort_key = None,encoding_errors ='replace',host_matching = False )

该类主要用来储存规则的集合

  • add(rulefactory ) 将新的Rule添加到MAP中

  • bind(server_name,script_name = None,subdomain = None,url_scheme ='http',default_method ='GET',path_info = None,query_args = None ) 绑定一个主机地址,并返回MapAdapter对象

  • bind_to_environ(environ,server_name = None,subdomain = None ) 将MAP绑定到WSGI环境中,并返回MapAdapter对象

  • iter_rules(endpoint = None ) 迭代所有Rule对象

MapAdapter(map,server_name,script_name,subdomain,url_scheme,path_info,default_method,query_args = None )

该类主要从Map.bind()或Map.bind_to_environ()返回MapAdapter对象,通过匹配规则,查找对应的endpoint,用来调用处理有关url的响应

  • match(path_info = None,method = None,return_rule = False,query_args = None ) 执行查找对应的规则,返回(endpoint, arguments)组成的元组

  • dispatch(view_func,path_info = None,method = None,catch_http_exceptions = False ) 首先执行match方法,然后执行endpoint对应的视图函数

你可能感兴趣的:(Werkzeug)