(2022.01.16 Sun)
Django执行Request-Response的流程/生命周期
- 用户通过浏览器/client发送用户请求request
- web server, e.g., Apache/Nginx,接收到请求。Django/Flask也有内置web server用于接收请求
- WSGI,i.e., socket服务端,接收来自webserver的用户请求并进行初次封装,并发送给web应用/框架,i.e., Django/Flask
- 经过WSGI封装的信息会发送给web应用,即Django。首先经过Django中间件,被中间件逐个处理
- URL路由器(URL router)接收到经过中间件处理的请求,并根据请求中URL地址,从视图views中的方法匹配web应用中可用的URL
- 被匹配关联的view方法处理接收到的请求,即处理业务逻辑(biz logic)
- view方法处理过程中可能设计调用ORM和后台数据库
- view方法处理过程中会调用context processor,对请求数据做context processing并经过template renderers的渲染,可返回一个HttpResponse
- 响应HttpResponse从view函数发送给中间件,并逐层处理
- WSGI对接收到的来自中间件的相应数据执行处理
- web server接收到WSGI的响应数据并发送给客户的brower
- client/browser收到web server的数据并展示请求结果
说明
- 中间件执行按照在
setting.py
中定义的顺序,Django request follows the order of middleware while processing the request. - 每个中间件都有一个类,每个类都有
process_request
方法
Web Server 网络服务器
(2022.01.17 Mon)
Web server is a software and hardware that use HTTP, SMTP, FTP and other protocols to respond to client request over WWW.网络服务器用于存储、处理和展示服务器上保存的页面信息给用户。网络服务器的硬件连接互联网,并与其他设备进行数据交换;网络服务器的软件控制用户如何访问宿主文件。所有网页必须有网络服务器软件才能被网络上其他节点访问。
网络服务器的功能,简单来说,是接收网络上用户的请求,处理信息,并提供响应。
网络服务器如何响应?
- 用户在本地电脑的浏览器中输入所请求的网页URL
- 浏览器根据URL获取IP地址,或者通过DNS查找,或者在缓存中检索到
- 浏览器向网页IP发送请求,包括所请求的网页和文件,以HTTP协议
- 网络服务器向浏览器返回所请求页面,如果页面不存在或访问出错,则返回
error
信息 - 浏览器显示返回的内容
动态dynamic和静态static页面
静态内容指的是显示的内容与保存的内容相同, i.e., static content is being shown as it is。而动态内容可以被更新和改变。
静态网页服务器包含服务器硬件和HTTP软件。
动态网页服务器包含服务器硬件,应用服务(application server)和数据库。
如果不安装web server,Django会使用其内置web server(Python Simple HTTPserver),不适合生产环境,高请求下响应成功率低。Flask类似。可使用Nginx作为Django服务的web server。可用的web server+WSGI的组合包括Nginx+uWSGI,Nginx+Gunicorn
WSGI和ASGI
(2022.01.18 Tues)
WSGI, i.e., Wet Server Gateway Interface,it is the specification for the interface between web server and web applications for Python, e.g., Django and Flask. Once upon a time Python has no standardised way to interface between production level web server and web application.
WSGI是一种web server和web application通信的规范或协议。WSGI被提出,成为底层接口标准(low level standard),连接web server和web应用诸如Django和Flask。WSGI像一条纽带,将web server与python web application, i.e., Django/Flask,连接起来。client来的请求,首先被web server接收,传送给WSGI,经过处理传送给web application。响应数据的过程与此过程相反。
WSGI如何参与web应用的响应?
web server比如Nginx、反向代理或负载均衡器接收到来自client浏览器的初始请求,之后其将请求委托(delegate)给WSGI服务器或WSGI应用的宿主容器。当WSGI服务器或容器接受了请求,会调用恰当的WSGI应用句柄(或处理handle)函数或callable,将HTTP请求转换为WSGI规定的可以用于被Python处理的格式。这之后,纯Python开始运行。
Web servers like Nginx, Apache, other reverse proxies, and load balancers accept the initial request from the client (the browser the end user is using), it then delegates the request to the WSGI server or WSGI application hosting container being used. When the WSGI server or container accepts the request it calls the appropriate WSGI application handler function or callable. From this point on, the work of pure Python starts.
WSGI的另一种理解
(2022.01.22 Sat)
一个标准和典型的web应用流程如下:
- 浏览器发送请求
- web应用接收到请求,并生成HTML文档作为响应
- web应用将HTML文档作为响应的body发送给客户端
- 客户端接收到响应,取出body并展示HTML
在这个过程中,web应用本质是一个socket服务端,用户是socket客户端。
在web应用处理响应的过程中,包括对HTTP请求和响应的处理,HTML的解析和生成,响应内容填充到HTML文档中等等。其中任何涉及HTTP解析的部分,比如HTTP接收请求、解析请求、发送响应,都需要深度了解HTTP协议和规范。另外关于TCP/IP的连接,HTML文件的格式等等,也是底层性质的基础工作。理想情况是web应用仅仅处理业务请求,即如何响应球球,而这些基础性质的繁重工作交给一个统一的接口完成,接口处理业务以外的部分工作。这个接口就是WSGI。
WSGI规范
WSGI (HTTP) server调用一个function/callable处理用户请求,这被称之为WSGI应用。它可以是一个函数,也可以是含有__call__
方法的可调用对象。该函数接受两个参数:
- environ:字典,包含用户请求的所有信息,包括一些metadata
- start_response函数:用于初始化响应。该函数接受两个参数,1) HTTP状态行,2) 可迭代形式的key-value pair表示的header.
WSGI应用的返回结果必须是一个可迭代形式的相应数据,每个元素的格式为byte(在python3中)。下面是一个demo
def wsgi_application(environment, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return [b'Hello, World\n', b'I am ready to go']
(2022.01.22 Sat)
注意,start_respose
方法返回了HTTP响应的header文件,而wsig_application
方法的响应是HTTP响应的body文件。其中的header文件只能发送一次,也就是start_response
方法只能调用一次。
下面是WSGI server实现了web应用的案例,代码来自博客园chasui
# 这是一个标准的application object
def index(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ['index page']
# 这是一个标准的application object
def hello(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return ['hello page']
# 这是一个标准的application object
def not_found(environ, start_response):
start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
return ['Not Found Page']
###上面我们定义了三个app
### 然后我们定义一个中间件 middleware, 看到没有,这个中间件的形式是跟app是一样的
def application(environ, start_response):
path = environ.get('PATH_INFO', '').lstrip('/') #这句代码是获取url
urls = [ # 这里定义路由
('index', index),
('hello', hello)
]
for item in urls: # 这里根据路由,执行不同的app
if item[0] == path:
app = item[1]
return app(environ, start_response)
else: return not_found(environ, start_response) # 如果找不到,则执行默认的app
from wsgiref.simple_server import make_server
# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
httpd.serve_forever()
WSGI是一种协议,其实现方式有多种,如uWSGI,werkzeug in Flask,gunicorn等。
WSGI的实现方式
placeholder
Django中如何实现假设WSGI server
placeholder
ASGI
(2022.01.26 Wed)
ASGI, a.k.a., Asynchronous Server Gateway Interface,继承了WSGI的功能,但却是WSGI的超集。在ASGI中,所有来自client的数据和application发送给客户端的数据,都是以消息事件(event?)的形式发送给protocol server处理,而request的结束只取决于application发送固定格式的event。ASGI支持WebSocket协议,支持长连接应用,如在线游戏和即时通信等需要长时间保持连接的应用。
ASGI结构是一个single, asynchronous的可调用函数。它的参数包括1) scope
,也就是包含某个特定连接细节的字典,2) send
,一个非同步可调用函数(asynchronous callable),应用通过它向客户端发送event messages,和3) receive
,一个非同步可调用函数,应用可通过它接收来自client的event messages。
ASGI的这种结构不仅保证了每个应用可以有多个到来事件(incoming event)和发出事件(outgoing event),而且也允许后台协程(background coroutine)也就是应用可以在后台执行其他任务。
下面是一个以最简形式的异步函数写成的应用
async def application(scope, receive, send):
event = await receive()
...
await send({'type': 'websocket.send', ...})
这里的每一个发送或接收到的事件都是一个Python字典,有固定格式。也正是这些事件格式形成了标准的根基,允许服务器之间的应用可以交换。
这里的事件都有type
键(key),用于指明(infer)事件结构(event structure)。下面是一个可以从HTTP请求中接收到的事件案例
{
"type": "http.request",
"body": b"hi Smartisan!",
"more_body": False,
}
下面是一个用于发送给WebSocket信息的事件案例
{
"type": "websocket.send",
"text": "hi Smartisan",
}
(2022.03.17 Thur)
Django官方推荐使用channel实现WedSocket,参考文献7.
中间件
(2022.01.16 Sun)
Middleware is a software lies between an operation system and application on it. Essentially functioning as hidden translation layer, middleware enables communication and data management for distributed application. It's sometimes called plumbing, as it connects two applications together so data and databases can be easily processed between the pipes.
中间件是一类软件,在不同应用之间,或系统与应用之间,建立通信的桥梁,用于为连接两端提供通信功能,如数据传输等。中间件包括,database middleware, application layer middleware, message-oriented middleware, web middleware等等。各类MQ就是中间件。
Django的中间件是修改Request或Response对象的钩子,是介于HttpRequest和HttpResponse之间的一道处理过程。HttpRequest-->中间件(用于修改请求)-->view functions-->中间件(用于修改响应)-->HttpResponse。
中间件执行了除了请求和响应意外的一些额外的操作,比如1) Django项目中默认启用了csrf保护,每次请求时通过CSRF中间件检查请求中是否有正确#token值,2) 当用户在页面上发送请求时,通过自定义的认证中间件,判断用户是否已经登陆,未登陆就去登陆,3)当有用户请求过来时,判断用户是否在白名单或者在黑名单里。
CSRF
CSRF, a.k.a., Cross Site Request Forgery,用于Django提供的防止伪装提交请求。
HTML的form表格后面有一个{% csrf_token %}的标签。POST 方法提交的表格,必须有此标签。
jinji2
Reference
1 Red Hat
2 Azure
3 百度百科
4 learnBATTA
5 博客园:Hu知非,chasui
6 https://asgi点readthedocs点io/en/latest/introduction.html
7 https冒号//channels点readthedocs.io/en/stable/