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相关推荐

  1. Flask werkzeug 源码解析

    Flask werkzeug流程大概:执行run_simple ,实际执行为先用make_server 创建一个 BaseServer 实例,然后执行 实例的serve_forever 方法, ser ...

  2. Laravel源码解析之Response

    之前两篇文章分别讲了Laravel的控制器和Request对象,在讲Request对象的那一节我们看了Request对象是如何被创建出来的以及它支持的方法都定义在哪里,讲控制器时我们详细地描述了如何找 ...

  3. spring boot2.x设置session有效时间_Spring 源码解析 Scopes 之 Request 、Session 、Application...

    (给ImportNew加星标,提高Java技能) 转自:开源中国,作者:麦克斯 链接:my.oschina.net/wang5v/blog/3017934 Request.Session.Applic ...

  4. python flask源码解析_用尽洪荒之力学习Flask源码

    [TOC] 一直想做源码阅读这件事,总感觉难度太高时间太少,可望不可见.最近正好时间充裕,决定试试做一下,并记录一下学习心得. 首先说明一下,本文研究的Flask版本是0.12. 首先做个小示例,在p ...

  5. Falsk session 源码解析

    Falsk框架session请求流程 from flask import Flask # 1. 实例化Flask对象 app = Flask(__name__) # 2. 设置路由 @app.rout ...

  6. Colly源码解析——结合例子分析底层实现

    通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...

  7. 彻底理解OkHttp - OkHttp 源码解析及OkHttp的设计思想

    OkHttp 现在统治了Android的网络请求领域,最常用的框架是:Retrofit+okhttp.OkHttp的实现原理和设计思想是必须要了解的,读懂和理解流行的框架也是程序员进阶的必经之路,代码 ...

  8. spring MVC cors跨域实现源码解析

    spring MVC cors跨域实现源码解析 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就是跨域. sp ...

  9. Volley 源码解析之图片请求

    一.前言 上篇文章我们分析了网络请求,这篇文章分析对图片的处理操作,如果没看上一篇,可以先看上一篇文章Volley 源码解析之网络请求.Volley 不仅仅对请求网络数据作了良好的封装,还封装了对图片 ...

最新文章

  1. 测试数据库sql声明效率
  2. asp服务器_200行代码,7个对象——让你了解ASP.NET Core框架的本质「3.x版」
  3. Codeforces Global Round 14 E. Phoenix and Computers 思维 + dp
  4. Java 集合 List Arrays.asList
  5. wallpaper怎么导入视频_快速制作视频字幕,我们推荐这款可视化字幕软件!
  6. elasticsearch控制返回字段查询三(英文分词)match查询
  7. python爬虫requests简单案例_python网络爬虫(三)requests库的13个控制访问参数及简单案例...
  8. 子窗体闭关后刷新父窗体内容
  9. HTML:如何创建表格
  10. php项目部署到服务器
  11. 计算机启动时检测硬盘,电脑总是启动检测硬盘怎么办
  12. 实验吧-简单的登录题
  13. Java实验项目三——平面图形和立体图形抽象类
  14. Sentry For Vue 完整接入详解(2021 Sentry v21.8.x)前方高能预警!三万字,慎入!
  15. win7中能对窗口的排列方法是_win7系统窗口智能排列的操作方法
  16. 【Java字符串分割[split()]和截取[substring()]】
  17. 职场语言的特征3p1A7C指什么,商务礼仪选择题和答案
  18. crossorigin
  19. 你想过吗,为什么说面向对象最符合人的思维?
  20. 聚米优选:“文学式vlog”主播,这么猛的吗?

热门文章

  1. 安装Windows 7的XP模式
  2. faiss python安装_faiss部署初体验
  3. 管理类联考——写作——素材篇——论说文——写作素材02——志篇:毅力·坚持
  4. 红鸟沙龙(09)|金灿荣:百年变局与中美关系
  5. 手机测试充电宝软件,记者随机测试5款产品 “有共享充电宝半小时只充了11%”...
  6. Map实现线程安全的3种方式
  7. 牛客 — 网络选择题练习中自己的错题(5)
  8. 微信小程序动画-倒计时缩放
  9. Unity中打开键盘+平板打开键盘+windows打开默认小键盘
  10. R7000P双系统装机记录