обо мне
Небольшой программист в мире программирования, в настоящее время работает руководителем команды в предпринимательской команде.Стек технологий включает Android, Python, Java и Go, который также является основным стеком технологий нашей команды. Контакт: hylinux1024@gmail.com
0x00 Что такое WSGI
Web Server Gateway Interface
это состоит изPython
Стандарт определяет наборWeb Server
иWeb Application
изСпецификация взаимодействия интерфейса.
WSGI
Не приложение, фреймворк, модуль или библиотека, а спецификация.
это чтоWeb Server
(Web
сервер) и что такоеWeb Application
(Web
применение)?
Примеры легко понять, например, общиеWeb
Каркас приложения имеетDjango
,Flask
подожди, покаWeb
сервер имеетuWSGI
,Gunicorn
Ждать.WSGI
Он должен определить спецификацию взаимодействия интерфейса между двумя концами.
0x01 Что такое Werkzeug
Werkzeug is a comprehensive WSGI web application library.
Werkzeug
это набор реализацийWSGI
Стандартная библиотека функций. Мы можем использовать его для созданияWeb Application
(Web
применение).例如本文介绍的Flask
Каркас приложения основан наWerkzeug
развивать.
Здесь мы используемWerkzeug
Запустите простое серверное приложение
from werkzeug.wrappers import Request, Response
@Request.application
def application(request):
return Response('Hello, World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, application)
После запуска в консоли можно увидеть следующую информацию
* Running on http://localhost:4000/ (Press CTRL+C to quit)
Открыть в браузереhttp://localhost:4000/Инструкции см. в следующей информации.
Hello, World!
0x02 Что такое фляга
Flask is a lightweight WSGI web application framework.
Flask
легкийweb
каркас приложения, который работает наweb
Приложение на сервере.Flask
Нижний слой инкапсулированWerkzeug
.
использоватьFlask
разрабатыватьweb
Приложение очень простое
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return f'Hello, World!'
if __name__ == '__main__':
app.run()
Просто как тот.
Далее посмотримFlask
Процесс запуска приложения.
0x03 запуск процесса
с адреса проектаGitHub.com/pallets/Фала…Исходный код центраclone
вниз, затем переключитесь на версию 0.1tag
. Зачем использовать версию 0.1? Поскольку это версия, написанная автором в начале, объем кода должен быть минимальным, и легко увидеть общие идеи автора по кодированию.
Ниже самый простойDemo
начать искатьFlask
как начать.我们知道程序启动是执行了以下方法
if __name__ == '__main__':
app.run()
и
app = Flask(__name__)
ОткрытымFlask
в исходном коде__init__
метод
Flask.init()
def __init__(self, package_name):
#: 是否打开debug模式
self.debug = False
#: 包名或模块名
self.package_name = package_name
#: 获取app所在目录
self.root_path = _get_package_path(self.package_name)
#: 存储视图函数的字典,键为函数名称,值为函数对象,使用@route装饰器进行注册
self.view_functions = {}
#: 存储错误处理的字典. 键为error code, 值为处理错误的函数,使用errorhandler装饰器进行注册
self.error_handlers = {}
#: 处理请求前执行的函数列表,使用before_request装饰器进行注册
self.before_request_funcs = []
#: 处理请求前执行的函数列表,使用after_request装饰器进行注册
self.after_request_funcs = []
#: 模版上下文
self.template_context_processors = [_default_template_ctx_processor]
#: url 映射
self.url_map = Map()
#: 静态文件
if self.static_path is not None:
self.url_map.add(Rule(self.static_path + '/<filename>',
build_only=True, endpoint='static'))
if pkg_resources is not None:
target = (self.package_name, 'static')
else:
target = os.path.join(self.root_path, 'static')
self.wsgi_app = SharedDataMiddleware(self.wsgi_app, {
self.static_path: target
})
#: 初始化 Jinja2 模版环境.
self.jinja_env = Environment(loader=self.create_jinja_loader(),
**self.jinja_options)
self.jinja_env.globals.update(
url_for=url_for,
get_flashed_messages=get_flashed_messages
)
существуетFlask
Различные операции инициализации выполняются в конструкторе .
Тогда естьвоплощать в жизньapp.run()
метод
app.run()
def run(self, host='localhost', port=5000, **options):
"""启动本地开发服务器. 如果debug设置为True,那么会自动检查代码是否改动,有改动则会自动执行部署
:param host: 监听的IP地址. 如果设置为 ``'0.0.0.0'``就可以进行外部访问
:param port: 端口,默认5000
:param options: 这个参数主要是对应run_simple中需要的参数
"""
from werkzeug.serving import run_simple
if 'debug' in options:
self.debug = options.pop('debug')
options.setdefault('use_reloader', self.debug)
options.setdefault('use_debugger', self.debug)
return run_simple(host, port, self, **options)
run
Очень лаконично, в основном по вызовуwerkzeug.serving
серединаrun_simple
метод.
открыть сноваrun_simple
исходный код
rum_simple()
def run_simple(hostname, port, application, use_reloader=False,
use_debugger=False, use_evalex=True,
extra_files=None, reloader_interval=1, threaded=False,
processes=1, request_handler=None, static_files=None,
passthrough_errors=False, ssl_context=None):
# 这方法还是比较短的,但是注释写得很详细,由于篇幅问题,就把源码中的注释省略了
if use_debugger:
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(application, use_evalex)
if static_files:
from werkzeug.wsgi import SharedDataMiddleware
application = SharedDataMiddleware(application, static_files)
def inner():
make_server(hostname, port, application, threaded,
processes, request_handler,
passthrough_errors, ssl_context).serve_forever()
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
display_hostname = hostname != '*' and hostname or 'localhost'
if ':' in display_hostname:
display_hostname = '[%s]' % display_hostname
_log('info', ' * Running on %s://%s:%d/', ssl_context is None
and 'http' or 'https', display_hostname, port)
if use_reloader:
# Create and destroy a socket so that any exceptions are raised before
# we spawn a separate Python interpreter and lose this ability.
test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
test_socket.bind((hostname, port))
test_socket.close()
run_with_reloader(inner, extra_files, reloader_interval)
else:
inner()
существуетrum_simple
Метод также определяет вложенный методinner()
, это основная часть метода.
inner()
def inner():
make_server(hostname, port, application, threaded, processes, request_handler, passthrough_errors, ssl_context).serve_forever()
существуетinner()
метод, вызовmake_server(...).serve_forever()
Служба запущена.
make_server()
def make_server(host, port, app=None, threaded=False, processes=1,
request_handler=None, passthrough_errors=False,
ssl_context=None):
"""Create a new server instance that is either threaded, or forks
or just processes one request after another.
"""
if threaded and processes > 1:
raise ValueError("cannot have a multithreaded and "
"multi process server.")
elif threaded:
return ThreadedWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context)
elif processes > 1:
return ForkingWSGIServer(host, port, app, processes, request_handler,
passthrough_errors, ssl_context)
else:
return BaseWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context)
существуетmake_server()
соответствует количеству потоков или процессов, которые будут созданы вWSGI
сервер.Flask
создается по умолчаниюBaseWSGIServer
сервер.
BaseWSGIServer, ThreadedWSGIServer, ForkingWSGIServer
class BaseWSGIServer(HTTPServer, object):
...
class ThreadedWSGIServer(ThreadingMixIn, BaseWSGIServer):
"""A WSGI server that does threading."""
...
class ForkingWSGIServer(ForkingMixIn, BaseWSGIServer):
"""A WSGI server that does forking."""
...
Видно, что их предыдущее отношение наследования выглядит следующим образом
ОткрытымBaseWSGIServer
изstart_server()
метод
start_server()
def serve_forever(self):
try:
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
Можно увидеть окончательное использованиеHTTPServer
中的启动服务的方法。 иHTTPServer
даPython
Интерфейсы в стандартной библиотеке классов.
HTTPServer
даsocketserver.TCPServer
подкласс
socketserver.TCPServer
Если вы хотите использоватьPython
Библиотека среднего класса запускаетhttp server
Похоже на код должен выглядеть так
import http.server
import socketserver
PORT = 8000
Handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()
В этот момент здесь начинается запуск всего сервиса.
Вызывающий процесс этого процесса
graph TD
A[Flask]-->B[app.run]
B[app.run]-->C[werkzeug.run_simple]
C[werkzeug.run_simple]-->D[BaseWSGIServer]
D[BaseWSGIServer]-->E[HTTPServer.serve_forever]
E[HTTPServer.serve_forever]-->F[TCPServer.serve_forever]
0x04 Суммировать
WSGI
даWEB
сервер сWEB
Спецификация интерфейса для взаимодействия между приложениями.werkzeug
Это для достижения стандартной библиотеки функции,Flask
каркас основан наwerkzeug
быть реализованным.
мы начинаем сFlask.run()
Метод запускает запуск службы, который отслеживает весь процесс запуска службы.