美文网首页
Flask入门2:Flask为什么可以独立运行

Flask入门2:Flask为什么可以独立运行

作者: 西西里加西 | 来源:发表于2020-04-17 23:18 被阅读0次

借助于app.run(),就可以让Flask程序启动起来,并且提供Web服务,但是一般我们都知道需要部署服务器并启动http服务才能启动web服务呀,那Flask是怎么实现的呢? 下面研究一下run()的源码:

from werkzeug.serving import run_simple

try:
    run_simple(host, port, self, **options)
        
finally:
# reset the first request information if the development server
# reset normally.  This makes it possible to restart the server
# without reloader and that stuff from an interactive shell.
    self._got_first_request = False

从上面的app.run()源码可以看出,run() 调用 werkzeug.serving 的 run_simple 方法,主动绑定IP,监听端口,调用程序等,开始提供服务。

那 Werkzeug 是什么?

Werkzeug 是一个 WSGI 工具包,也可以作为一个Web框架的底层库。WSGI 叫Web服务网关接口,用于定义Web服务器 和 Python Web程序通信的接口规范 ,是一种协议(规范)。

Web服务器在接受到请求之后,经过处理,可以通过WSGI将数据发给Python Web程序处理。如果没有 WSGI ,程序和服务器之间没有办法进行交互。

image

当客户端发出一个 HTTP 请求后,是如何转到Flask处理并返回的呢?

image

刚才我们用到的是是第一种架构,在这种结构里,uWSGI作为服务器,它用到了HTTP协议以及wsgi协议,Flask应用作为application,实现了wsgi协议。当有客户端发来请求,uWSGI接受请求,调用Flask app得到相应,之后相应给客户端。这里说一点,通常来说,Flask等web框架会自己附带一个WSGI服务器 (这就是Flask应用可以直接启动的原因app.run() 启动了这个WSGI服务器),但是这只是在开发阶段用到的,在生产环境是不够用的,所以用到了uWSGI这个性能高的wsgi服务器。

WSGI:通信协议

uWSGI:uWSGI是一个全功能的HTTP服务器,实现了WSGI协议、uwsgi协议、http协议等。它要做的就是把HTTP协议转化成语言支持的网络协议。比如把HTTP协议转化成WSGI协议,让Python可以直接使用。

uwsgi:uWSGI服务器实现的独有的协议

下面来利用Werkzeug 来模拟 app.run()

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "hello, world!"

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('127.0.0.1', 5000, app, use_debugger=True)

接下来使用Werkzeug 来模拟 WSGI服务器 和 Flask实例化之后的APP 之间的数据交互的过程:

class myFlask(): # 自定义的,代替Flask类
    def __call__(self, *args, **kwargs): # 必须是可回调的,这样uWSGI才知道调用那个程序
        return 'hello, world!'

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = myFlask()
    run_simple('127.0.0.1', 5000, app, use_debugger=True)

运行之后发现,服务器可以启动,但是完成处理请求

image

这是因为WSGI 对于 application 对象有如下三点要求

  • 必须是一个可调用的对象
  • 接收两个必选参数environ、start_response
  • 返回值必须是可迭代对象,用来表示http body

并且通过debug信息及源码可知,错误的地方是直接return数据(write()),并没有设置响应头。所以uWSGI没有办法通过app所得数据对发送响应。

image

调整代码:

class myFlask():
    def __call__(self, environ, start_response):
        #利用start_response定义请求头
        start_response('200 ok', [('Content-Type', 'text/plain')])
        #需要返回字节对象
        return [b'hello, world!'] 

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = myFlask()
    run_simple('127.0.0.1', 5000, app, use_debugger=True)
image

利用上面的代码做个动态返回。

from werkzeug.wrappers import Request, Response

class myFlask():
    def __call__(self, environ, start_response):
        #使用Request来获取请求信息
        request = Request(environ) 
        #根据请求报文所带的get参数u来动态回应,默认值是jk
        text = 'hello {}'.format(request.args.get('u', 'jk'))
        #使用Response来实例化响应对象
        response = Response(text, mimetype="text/plain")
        #返回响应对象
        return response(environ, start_response)

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    app = myFlask()
    run_simple('127.0.0.1', 5000, app, use_debugger=True)
image image

上面我们使用Werkzeug 实现了一个web 服务。可以看出,Werkzeug 为开发者提供与web服务器进行WSGI通信的类、方法等,有了它,Flask就具备提供web服务的能力,开发者只需要关注Flask app的开发即可。

最后来看一下不同web网关协议之间的关系:

CGI是鼻祖,FastCGI做了加强,WSGI针对Python程序做了优化

image image image image

参考:

掘金:花了两个星期,我终于把 WSGI 整明白了

补充:

  • uWSGI 服务器的 uwsgi 协议干嘛的?究竟用在何处?

https://www.zhihu.com/question/46945479
https://www.xncoding.com/2017/01/20/python/uwsgi.html

相关文章

网友评论

      本文标题:Flask入门2:Flask为什么可以独立运行

      本文链接:https://www.haomeiwen.com/subject/bndpvhtx.html