Flask

overview

背景

Flask以及它所使用的wsgi库werkzeug和模板引擎jinja2都是由Armin Ronacher和他的团队开发的。实际上Armin Ronacher早就开发出来了werkzeug开源库,旨在为框架封装一个良好的底层的API接口,但过了一段时间,Armin发现还是自己来先做一个吧,然后Flask就诞生了。

任务

分析从发起HTTP请求到响应请求之间的流程

涉及源代码文件:

    • Flask源码

      • app.py
    • werkzeug源码
      • serving.py
    • python基本库源码

      • SocketServer.py
      • BaseHTTPServer.py
  • 先来看一个最小的Flask应用:
from flask import Flask
app = Flask(__name__) @app.route('/')
def hello_world():
return 'Hello World!' if __name__ == '__main__':
app.run()

显而易见,app.run是核心代码。我们来看一下app.py中相关的代码:

<app.py>
def run(self, host=None, port=None, debug=None, **options):
from werkzeug.serving import run_simple
run_simple(host, port, self, **options) <serving.py>
def run_simple(hostname, port, application, ...,
request_handler=None, static_files=None, ...):
srv = make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context,
fd=fd)
srv.serve_forever() def make_server(host=None, port=None, app=None, threaded=False, processes=1,
request_handler=None, passthrough_errors=False,
ssl_context=None, fd=None):
return BaseWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)

可以看到实际上是make了一个BaseWSGIServer,这个server开始监听连接。下边来研究一下这个BaseWSGIServer。
BaseWSGIServer继承自python基本库BaseHTTPServer.py中的HTTPServer, HTTPServer继承自SocketServer.py中的TCPServer。

<serving.py>
class BaseWSGIServer(HTTPServer, object):
def __init__(self, host, port, app, handler=None, ...):
if handler is None:
handler = WSGIRequestHandler
HTTPServer.__init__(self, (host, int(port)), handler)
self.app = app class HTTPServer(SocketServer.TCPServer):
def server_bind(self):
.... class TCPServer(BaseServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise <SocketServer.py>
class BaseServer:
def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False def serve_forever(self, poll_interval=0.5):
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
r, w, e = _eintr_retry(select.select, [self], [], [],
poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set() def finish_request(self, request, client_address):
# 这里非常重要,就是实例化请求处理类
self.RequestHandlerClass(request, client_address, self)

从这些代码可以看出,HTTP建立于TCP之上。BaseServer最需要注意的是在构造的时候设置了请求处理类RequestHandlerClass。也就是在BaseWSGIServer构造的时候设置了请求处理类。根据上边的了解,我们知道在app.run()的时候就把请求处理类设置好了,注意这里只是设置了请求处理类,并没有真正的去构建一个处理实例。那么它是在什么时候实例化呢?实际上它是在http请求真正到来的时候才会被实例化。随后我们会继续通过代码看到这个请求处理类在实例化的时候就会自动去处理这个请求。
我们先来简单说一下一个请求的基本处理逻辑。

1.首先一个连接进来,BaseServer监听到连接,调用self._handle_request_noblock()处理
2.self._handle_request_noblock()最终找到finish_request方法
3.finish_request方法实例化请求处理类RequestHandlerClass
BaseWSGIServer的构造函数中,我们看到如果我们不自己实现请求处理句柄的话,就会使用werkzeug库提供的WSGIRequestHandler。我们再来看一下这个类到底是一个什么东西。

<serving.py>
class WSGIRequestHandler(BaseHTTPRequestHandler, object):
def handle(self):
rv = BaseHTTPRequestHandler.handle(self)
return rv
def handle_one_request(self):
self.raw_requestline = self.rfile.readline()
if not self.raw_requestline:
self.close_connection = 1
elif self.parse_request(): # 从tcp到http中间的处理逻辑
return self.run_wsgi() # 真正的处理,随后我们会拿出来研究一下
def run_wsgi(self):
pass <BaseHTTPServer.py>
class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
def parse_request(self):
...
def handle(self):
self.handle_one_request() <SocketServer.py>
class StreamRequestHandler(BaseRequestHandler):
def setup(self):
...
def finish(self):
... class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server # 这个非常重要,设置了request的server,我们随后会看到
self.setup()
try:
self.handle()
finally:
self.finish()

一层一层的继承下来,实际上就是继承的python基本库里的基本请求处理类。这个类在实例化的时候会调用handle函数处理,handle函数我们在WSGIRequestHandler中复写了,handle函数会调用我们在WSGIRequestHandler中复写的handle_one_request函数。好了,终于找到头了。我们看一下这个run_wsgi是怎么处理的。函数稍微长一些,我们拣逻辑性的重要代码分析一下。

def run_wsgi(self):
def write(data):
...
self.wfile.write(data) # 回复响应数据
def start_response(status, response_headers, exc_info=None):
...
return write
def execute(app):
application_iter = app(environ, start_response)
for data in application_iter:
write(data)
execute(self.server.app)

代码很清楚,就是调用了app来处理请求,然后app匹配url找到视图view,真正的处理。你说app是怎么来的?我们上边研究过了,它是在请求到来的时候,由server传递给请求处理类的。也就是说只有当请求连接的时候,才会实例化处理类,处理类在实例化的时候就会配置它的server。就是下边的代码。

 <SocketServer.py>
class BaseServer:
def finish_request(self, request, client_address):
# 这里非常重要,就是实例化请求处理类
self.RequestHandlerClass(request, client_address, self) class BaseRequestHandler:
def __init__(self, request, client_address, server):
self.server = server <serving.py>
class BaseWSGIServer(HTTPServer, object):
def __init__(self, host, port, app, handler=None, ...):
self.app = app

好了,以上的流程我们都清楚了。下边就开始研究app(environ, start_response)的奇妙了。

https://blog.csdn.net/u010007589/article/details/70338066

https://blog.csdn.net/u010007589/article/details/50542251

字符串过滤掉所有最邻近的“<”和“>”之间的字符的更多相关文章

  1. 【编程题目】在一个字符串中找到第一个只出现一次的字符。如输入 abaccdeff,则输出 b。

    第 17 题(字符串):题目:在一个字符串中找到第一个只出现一次的字符.如输入 abaccdeff,则输出 b. 思路:此题非常容易. 最开始是想开辟一块空间存储每个字符出现的次数. 但转念一想,似乎 ...

  2. 一个字符串中可能包含a~z中的多个字符,如有重复,如String data="aavzcadfdsfsdhshgWasdfasdf",求出现次数最多的那个字母及次数,如有多个重复的则都求出。

    主要掌握String中的方法 char[] toCharArray()           将此字符串转换为一个新的字符数组. int indexOf(String str)           返回 ...

  3. C#返回字符串的字节长度,一个中文算两个字符的代码

    如下代码段是关于C#返回字符串的字节长度,一个中文算两个字符的代码. public static int GetLength(string str) { if (str.Length == 0) re ...

  4. Oracle把逗号分割的字符串转换为可放入in的条件语句的字符数列

    Oracle把逗号分割的字符串转换为可放入in的条件语句的字符数列   前台传来的字符串:'589,321' SELECT*FROM TAB_A T1 WHERE  T1.CODE  IN ( SEL ...

  5. 剑指offer-第五章优化时间和空间效率(在字符串中第一次出现切只出现一次的字符)

    题目:在字符串中第一次出现切只出现一次的字符 思路:用HashMap来存放对应的char值和该char出现的次数.做一次变量就可以得到第一个只出现一次的字符. Java代码: import java. ...

  6. 使你的C/C++代码支持Unicode(CRT字符串处理的所有API列表,甚至有WEOF字符存在)

    悉Microsoft支持Unicode的方式. 它的主要目的是方便你查询相关的数据类型和函数,以及修正相应的拼写错误. I18nGuy 主页 XenCraft (Unicode 咨询公司) Engli ...

  7. JS中substring()方法(用于提取字符串中介于两个指定下标之间的字符)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. 【leetcode-03】给定一个字符串,请你找出其中不含有重复字符的最长子串的长度

    开个新坑,leetcode上面做题目.下面是题目描述: <!-- 给定一个字符串,请你找出其中不含有重复字符的最长子串的长度. 示例 1: 输入: "abcabcbb" 输出 ...

  9. 2016/1/12 第一题 输出 i 出现次数 第二题 用for循环和if条件句去除字符串中空格 第三题不用endwith 实现尾端字符查询

    import java.util.Scanner; public class Number { private static Object i; /* *第一题 mingrikejijavabu中字符 ...

随机推荐

  1. SharePoint 2013 Step by Step—— How to Upload Multiple Documents in Document Library

    How to Upload Multiple documents in SharePoint 2013,Options to add multiple files in a document libr ...

  2. Oracle数据库中number类型在java中的使用

    1)如果不指定number的长度,或指定长度n>18 id number not null,转换为pojo类时,为java.math.BigDecimal类型 2)如果number的长度在10 ...

  3. tensorflow中使用Batch Normalization

    在深度学习中为了提高训练速度,经常会使用一些正正则化方法,如L2.dropout,后来Sergey Ioffe 等人提出Batch Normalization方法,可以防止数据分布的变化,影响神经网络 ...

  4. Elastalert 监控

    1.logstash 做监控的优劣 适合match-then-alert 的方式 logstash-filter-metric logstash-input-http_poller 无状态.进程间数据 ...

  5. Chris Richardson微服务实战系列

    微服务实战(一):微服务架构的优势与不足 微服务实战(二):使用API Gateway 微服务实战(三):深入微服务架构的进程间通信 微服务实战(四):服务发现的可行方案以及实践案例 微服务实践(五) ...

  6. 关于NOIP的运行环境

    目前(2019年2月22日)仍然是 G++ , 终端运行,命令行: g++ test.cpp -o test ,而g++ 4.8.4默认标准是: -std=gnu++ . g++到了gcc6才把默认标 ...

  7. 【Unity】6.8 Quaternion类(四元数)

    分类:Unity.C#.VS2015 创建日期:2016-04-20 一.四元数的概念 四元数包含一个标量分量和-个三维向量分量,四元数Q可以记作: Q=[w,(x,y,z)] 在3D数学中使用单位四 ...

  8. 【Unity】6.4 Transform--移动、旋转和缩放游戏对象

    分类:Unity.C#.VS2015 创建日期:2016-04-20 一.简介 Unity引擎提供了丰富的组件和类库,为游戏开发提供了非常大的便利,熟练掌握和使用这些API,对于游戏开发的效率提高很重 ...

  9. centos 7 忘记密码

    修改rd.lvm.lv=cl/swap(我的是虚似机如果是实体机的话应该是ro_rd.lvm.lv=centos/swap)改成 rw init=/sysroot/bin/sh 注意上图rw init ...

  10. 菜鸟学SSH(五)——Struts2上传文件

    上传文件在一个系统当中是一个很常用的功能,也是一个比较重要的功能.今天我们就一起来学习一下Struts2如何上传文件. 今天讲的上传文件的方式有三种: 1,以字节为单位传输文件: 2,Struts2封 ...