模块结构图大致如下(并没有完全列出模块所有内容)
我们需要实现一个apllication的函数或者类,然后传入envrion环境变量和start_response函数,返回一个可迭代的二进制流对象
我们需要实现一个遵循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()
这个模块主要包含了两个类:BaseRequest
,BaseResponse
外加多个MIXIN
类
BaseRequest(environ)
类 ,请求对象类这个类通过传入环境参数来读取浏览器的请求内容,是只读的.
使用@Request.application
装饰器,此装饰器是将一个函数装饰为application
传入装饰器的是environ
和start_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)
BaseResponse
和BaseRequest
的功能Reuquest MIXIN
AcceptMixin 用于接受头解析
ETagRequestMixin 用于etag和缓存控制处理
UserAgentMixin 用于用户代理内省
AuthorizationMixin 用于http身份验证处理
CommonRequestDescriptorsMixin 用于常见标题
Response MIXIN
ETagResponseMixin 用于etag和缓存控制处理
ResponseStreamMixin添加对流属性的支持
CommonResponseDescriptorsMixin 用于各种HTTP描述符
WWWAuthenticateMixin 用于HTTP身份验证支持
该模块主要为几种常用的结构
MultiDict(mapping)
类 是一个字典的子类,主要用来解析html表单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对应的视图函数