werkzeug源码解析 Request Response
werkzeug源码解析 Request Response
datastructures
- datastructures.py单元定义了基本类型
- 为了实现不可修改,定义了一系列Immutable类,通过覆盖默认的魔术方法(__delitem__,__setitem__等)使修改时抛异常
Request
- 继承关系werkzeug.wrappers.request.Request–>werkzeug.sansio.request.Request
werkzeug.sansio.request.Request
方法基本是对wsgi中environ进行解析,使用时更方便(url,access_route,cookies,host,mimetype,user_agent,args等)
# werkzeug.wrappers.request.Request初始化__init__调用super(werkzeug.sansio.request.Request)时入参 def __init__(self,environ: "WSGIEnvironment",populate_request: bool = True,shallow: bool = False,) -> None:super().__init__(method=environ.get("REQUEST_METHOD", "GET"),scheme=environ.get("wsgi.url_scheme", "http"),server=_get_server(environ),root_path=_wsgi_decoding_dance(environ.get("SCRIPT_NAME") or "", self.charset, self.encoding_errors),path=_wsgi_decoding_dance(environ.get("PATH_INFO") or "", self.charset, self.encoding_errors),query_string=environ.get("QUERY_STRING", "").encode("latin1"),headers=EnvironHeaders(environ),remote_addr=environ.get("REMOTE_ADDR"),)...
方法大多返回不可修改对象ImmutableMultiDict或ImmutableList
werkzeug.wrappers.request.Request
根据content-type解析http/https的body(environ[“wsgi.input”])
from werkzeug.wrappers import Request, Response from werkzeug.test import create_environenviron = create_environ(path='/foo', base_url='http://localhost:8080/', query_string="id=22&name=aaa", content_type="application/json", json={'param1': '666', 'param2': 'kkk'}) request = Request(environ) for key in list(request.__dict__.keys()):print(key, getattr(request, key))
Response
- 继承关系werkzeug.wrappers.response.Response–>werkzeug.sansio.response.Response
werkzeug.sansio.response.Response
- 和werkzeug.sansio.request.Request对应,封装http协议响应控制,status,headers(主要处理mimetype,content_type)
- 属性status和status_code是同步的,存储在_status, _status_code
werkzeug.sansio.response.Response
- 根据headers的content_type处理返回http内容body,存储在response
- Response是由业务绝对内容的,所以header和body必须在__init__中自己指定,不能像Request从environ解析且不可修改,至于get_wsgi_headers,get_app_iter等environ是用来确定Location等内容
Request和Response配合封装wsgi
- werkzeug.wrappers.request.Request.application和werkzeug.wrappers.response.Response.__call__配合封装WSGI流程
# 服务端
"""
探索werkzeug.wrappers.request.Request werkzeug.wrappers.response.Response使用
"""import json
from wsgiref.simple_server import WSGIServer, WSGIRequestHandler
from werkzeug import Request, Response@Request.application
def werkzeug_app(request):"""werkzeug.Request.application将wsgi入口application参数environ转为werkzeug.Request实例request被装饰函数werkzeug_app处理业务请求和放回,return werkzeug.Response实例werkzeug.Request.application调用werkzeug.Response实例,实例调用__call__内部调用了wsgi回调start_response回写status和headers,本身返回bodywerkzeug.Request.application完成了wsgi原始入参(environ, start_response) -> body到request -> response的转换进一步,基于werkzeug的框架重点在于路由管理,即werkzeug.Request作为框架入参,根据path method等路由到具体业务,返回werkzeug.Response"""body = {'method': request.method, 'path': request.path, 'query': request.query_string.decode('utf-8')}for k, v in request.json.items():body[k] = vreturn Response(response=json.dumps(body), status=200, content_type="application/json; charset=utf-8")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 serverif __name__ == '__main__':with make_server('', 8000, werkzeug_app) as httpd:httpd.serve_forever()# 客户端
from http.client import HTTPConnection
import jsondef client_demo():client = HTTPConnection('127.0.0.1', 8000)body = json.dumps({'param1': 'xxx', 'param2': 'yyy'}).encode('utf-8')headers = {'Content-Type': 'application/json', 'Content-Length': len(body)}client.request('POST', '/wsgi_text?user=go', body=body, headers=headers)respnese = client.getresponse()print(respnese.read().decode('utf-8'))if __name__ == '__main__':client_demo()
封装Application类
# 官方demo,Shortly相当于Application类,dispatch_request处理路由
import osfrom werkzeug.serving import run_simple
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.middleware.shared_data import SharedDataMiddlewarefrom jinja2 import Environment, FileSystemLoaderuser_count = {str(id): 0 for id in range(1, 10)}def index(request):return 'index.html', {'user_count': user_count}def user_details(request, user):if user_count.get(user, None) is None:raise NotFound()user_count[user] += 1return 'user_details.html', {'user': user, 'count': user_count[user]}def error_404():return "404.html"class Shortly(object):def __init__(self):self.template_path = os.path.join(os.path.dirname(__file__), "templates")self.jinja_env = Environment(loader=FileSystemLoader(self.template_path), autoescape=True)self.handle_404 = error_404self.url_map = Map([Rule("/index.html", endpoint=index),Rule("/<user>.html", endpoint=user_details),])def dispatch_request(self, request):adapter = self.url_map.bind_to_environ(request.environ)try:endpoint, values = adapter.match()template_name, context = endpoint(request, **values)return self.render_template(template_name, **context)except HTTPException as e:template_name, context = self.handle_404()response = self.render_template(template_name, **context)response.status = 404return responsedef wsgi_app(self, environ, start_response):request = Request(environ)response = self.dispatch_request(request)return response(environ, start_response)def __call__(self, environ, start_response):return self.wsgi_app(environ, start_response)def render_template(self, template_name, **context):t = self.jinja_env.get_template(template_name)return Response(response=t.render(context), mimetype='text/html')def create_app():app = Shortly()app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {"/static": os.path.join(os.path.dirname(__file__), "static")})return appif __name__ == '__main__':run_simple('127.0.0.1', 5000, create_app(), use_debugger=True, use_reloader=True)
<!templates/layout.html>
<!doctype html>
<title>{% block title %}{% endblock %} | shortly</title>
<link rel=stylesheet href=/static/style.css type=text/css>
<div class=box><h1><a href= />shortly</a></h1><p class=tagline>Shortly is a URL shortener written with Werkzeug{% block body %}{% endblock %}
</div><!templates/index.html>
{% extends "layout.html" %}
{% block title %}All User{% endblock %}
{% block body %}
<table><caption>All User</caption><thead><tr><th>user</th><th>count</th></tr></thead><tbody>{% for user, count in user_count.items() %}<tr><th><a href="/{{user}}.html">{{user}}</th><th>{{count}}</th></tr>{% endfor %}</tbody>
</table>
{% endblock %}<!templates/user_details.html>
{% extends "layout.html" %}
{% block title %}Details about {{ user }}{% endblock %}
{% block body %}
<p> user:{{ user }} count:{{ count }}</p>
{% endblock %}<!templates/404.html>
{% extends "layout.html" %}
{% block title %}Page Not Found{% endblock %}
{% block body %}<h2>Page Not Found</h2><p>I am sorry, but no such page was found here.
{% endblock %}
# static/style.css
body { background: #E8EFF0; margin: 0; padding: 0; }
body, input { font-family: 'Helvetica Neue', Arial,sans-serif; font-weight: 300; font-size: 18px; }
.box { width: 500px; margin: 60px auto; padding: 20px;background: white; box-shadow: 0 1px 4px #BED1D4;border-radius: 2px; }
a { color: #11557C; }
h1, h2 { margin: 0; color: #11557C; }
h1 a { text-decoration: none; }
h2 { font-weight: normal; font-size: 24px; }
.tagline { color: #888; font-style: italic; margin: 0 0 20px 0; }
.link div { overflow: auto; font-size: 0.8em; white-space: pre;padding: 4px 10px; margin: 5px 0; background: #E5EAF1; }
.error { background: #E8EFF0; padding: 3px 8px; color: #11557C;font-size: 0.9em; border-radius: 2px; }
.urlinput { width: 300px; }
werkzeug源码解析 Request Response相关推荐
- Flask werkzeug 源码解析
Flask werkzeug流程大概:执行run_simple ,实际执行为先用make_server 创建一个 BaseServer 实例,然后执行 实例的serve_forever 方法, ser ...
- Laravel源码解析之Response
之前两篇文章分别讲了Laravel的控制器和Request对象,在讲Request对象的那一节我们看了Request对象是如何被创建出来的以及它支持的方法都定义在哪里,讲控制器时我们详细地描述了如何找 ...
- spring boot2.x设置session有效时间_Spring 源码解析 Scopes 之 Request 、Session 、Application...
(给ImportNew加星标,提高Java技能) 转自:开源中国,作者:麦克斯 链接:my.oschina.net/wang5v/blog/3017934 Request.Session.Applic ...
- python flask源码解析_用尽洪荒之力学习Flask源码
[TOC] 一直想做源码阅读这件事,总感觉难度太高时间太少,可望不可见.最近正好时间充裕,决定试试做一下,并记录一下学习心得. 首先说明一下,本文研究的Flask版本是0.12. 首先做个小示例,在p ...
- Falsk session 源码解析
Falsk框架session请求流程 from flask import Flask # 1. 实例化Flask对象 app = Flask(__name__) # 2. 设置路由 @app.rout ...
- Colly源码解析——结合例子分析底层实现
通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...
- 彻底理解OkHttp - OkHttp 源码解析及OkHttp的设计思想
OkHttp 现在统治了Android的网络请求领域,最常用的框架是:Retrofit+okhttp.OkHttp的实现原理和设计思想是必须要了解的,读懂和理解流行的框架也是程序员进阶的必经之路,代码 ...
- spring MVC cors跨域实现源码解析
spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就是跨域. sp ...
- Volley 源码解析之图片请求
一.前言 上篇文章我们分析了网络请求,这篇文章分析对图片的处理操作,如果没看上一篇,可以先看上一篇文章Volley 源码解析之网络请求.Volley 不仅仅对请求网络数据作了良好的封装,还封装了对图片 ...
最新文章
- 测试数据库sql声明效率
- asp服务器_200行代码,7个对象——让你了解ASP.NET Core框架的本质「3.x版」
- Codeforces Global Round 14 E. Phoenix and Computers 思维 + dp
- Java 集合 List Arrays.asList
- wallpaper怎么导入视频_快速制作视频字幕,我们推荐这款可视化字幕软件!
- elasticsearch控制返回字段查询三(英文分词)match查询
- python爬虫requests简单案例_python网络爬虫(三)requests库的13个控制访问参数及简单案例...
- 子窗体闭关后刷新父窗体内容
- HTML:如何创建表格
- php项目部署到服务器
- 计算机启动时检测硬盘,电脑总是启动检测硬盘怎么办
- 实验吧-简单的登录题
- Java实验项目三——平面图形和立体图形抽象类
- Sentry For Vue 完整接入详解(2021 Sentry v21.8.x)前方高能预警!三万字,慎入!
- win7中能对窗口的排列方法是_win7系统窗口智能排列的操作方法
- 【Java字符串分割[split()]和截取[substring()]】
- 职场语言的特征3p1A7C指什么,商务礼仪选择题和答案
- crossorigin
- 你想过吗,为什么说面向对象最符合人的思维?
- 聚米优选:“文学式vlog”主播,这么猛的吗?
热门文章
- 安装Windows 7的XP模式
- faiss python安装_faiss部署初体验
- 管理类联考——写作——素材篇——论说文——写作素材02——志篇:毅力·坚持
- 红鸟沙龙(09)|金灿荣:百年变局与中美关系
- 手机测试充电宝软件,记者随机测试5款产品 “有共享充电宝半小时只充了11%”...
- Map实现线程安全的3种方式
- 牛客 — 网络选择题练习中自己的错题(5)
- 微信小程序动画-倒计时缩放
- Unity中打开键盘+平板打开键盘+windows打开默认小键盘
- R7000P双系统装机记录