Django之请求的本质
本质上django程序就是一个socket服务端,用户的浏览器其实就是一个socket客户端;
在遵循http协议的基础上两方进行通讯;
以django为例: 涉及到底层socket方面(接收和解析浏览器的请求信息, 响应头和响应体的发送都是由django的wsgi模块完成的,用户只需要实现路由和视图函数,模板等代码部分即可):
请求头和请求体以两个
\r\n
分隔开, 请求头的内容也是以\r\n
分开, 相应头和响应体同理;Cookie信息是在请求头和响应头中存放的;
// 在浏览器输入 http://127.0.0.1:8001/ 即可看到发送的信息
import socket
def handle_request(client):
# 相当于接收用户信息,在做出相应的反馈...
buf = client.recv(1024)
# response(响应头和响应体)
client.send("HTTP/1.1 200 OK\r\n\r\n<h1 style=‘color:red‘>Hello, yuan</h1>".encode("utf8"))
# 响应体也可以分开写
# client.send("<h1 style=‘color:red‘>Hello, yuan</h1>".encode("utf8"))
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((‘localhost‘, 8002))
sock.listen(5)
while True:
connection, address = sock.accept()
# 处理用户信息
handle_request(connection)
connection.close()
if __name__ == ‘__main__‘:
main()
自定义web框架
可以将这个三部分分为放在三个文件中,在bin主代码区导入urls和view函数即可;
# views文件 -------------------------------
def f1(request):
f = open("alex.html", ‘rb‘)
data = f.read()
f.close()
return [data]
def f2(request):
f = open("egon.html", ‘rb‘)
data = f.read()
f.close()
return [data]
def log_in(request):
f = open("login.html", ‘rb‘)
data = f.read()
f.close()
return [data]
def auth(request):
data = request.get(‘QUERY_STRING‘).strip().split("&")
username = data[0].split("=")[1]
password = data[1].split("=")[1]
print(username, password)
if username=="alex" and password=="abc123":
return [b"login success"]
else:
return [b"wrong username or password"]
def register(request):
f = open("register.html", ‘rb‘)
data = f.read()
f.close()
return [data]
# urls文件 ----------------------------------
def routers():
URLpattern = [
("/alex", f1),
("/egon", f2),
("/login", log_in),
("/auth", auth),
("/register", register)
]
return URLpattern
# bin文件 ---------------------------------
from wsgiref.simple_server import make_server
from .urls import routers
def application(environ, start_response):
# 1. 接收请求, 所有的请求信息都保存在environ对象中
path = environ.get("PATH_INFO") # 取出请求的文件路径名称
# 2. 向浏览器返回响应信息(响应头信息)
start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)])
url_patterns = routers() # 取出url和函数的键值对
# 3. 循环遍历(url)键值对,若匹配则赋值对应的函数
func = None
for item in url_patterns:
if path == item[0]:
func = item[1]
break
if func:
# 4. 调用视图函数, 返回响应体信息
return func(environ) # 注意,这里必须return调用函数,否则会报错!
else:
return [b"<h1>404</h1>"] # 列表中, 元素是二进制字节
s = make_server("127.0.0.1", 8800, application)
s.serve_forever()
Django之请求的生命周期
Django的请求生命周期是指当用户在浏览器上输入url到用户看到网页的这个时间段内,Django程序内部所发生的事情;
具体步骤如下:
- 当用户在浏览器输入url时, 然后浏览器会生成请求头和请求体发送给服务器;
- url经过wsgi---中间件---最后到达路由映射表, 按顺序进行正则匹配,若匹配到,则进入对应的视图函数或者类(CBV)中;
- 视图函数根据客户端的请求,取出数据并渲染到模板中,其中可能涉及ORM操作(增删改查)或从缓存取出数据, 最终以字符串的形式返回;
CBV模式
工作原理
- 一个url对应一个视图类
- 用户提交HTTP请求之后, 经过过wsgi和中间件,最后到URL路由, 再判断出是走哪个类,接着进入views相关的类, 然后此类调用父类的
dispatch()
,dispatch会根据http请求头里的method
是get
还是post
方法来执行相应的函数。
Dispatch结合session实现用户授权访问
方法1: 直接在类中重载dispaych方法
弊端: 代码重复使用!
from django.views import View
class LoginView(View):
def get(self, request):
return render(request, ‘login.html‘)
def post(self, request):
request.session[‘user_info‘] = {‘username‘: ‘bob‘, ‘info‘: ‘‘}
return redirect(‘/index.html‘)
class IndexView(View):
def dispatch(self, request, *args, **kwargs):
# 不存在session信息则直接跳转至登录界面
if not request.session.get(‘user_info‘, ‘‘):
return redirect(‘/login.html‘)
ret = super(IndexView, self).dispatch(request, *args, **kwargs)
return ret
def get(self, request):
return render(request, ‘index.html‘)
方法2: 使用装饰器
内置的装饰器csrf_exempt
是特例,只能装饰dispatch函数才能起到作用,是的post请求无须通过csrf中间件的验证
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
def test(func):
"""装饰器函数"""
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
class LoginView(View):
# 方式1,作用于dispatch函数
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
ret = super(LoginView, self).dispatch(request, *args, **kwargs)
print(‘login after‘)
return ret
# 方式2: 装饰get函数
# @method_decorator()
def get(self, request):
return render(request, ‘login.html‘)
# @method_decorator(csrf_exempt)
def post(self, request):
username = request.POST.get(‘username‘, ‘‘)
password = request.POST.get(‘password‘, ‘‘)
if username and password:
request.session[‘user_info‘] = {‘user‘:username, ‘pwd‘:password}
return redirect(‘/index.html‘)
else:
return render(request, ‘login.html‘)
# @method_decorator(func)
class IndexView(View):
def dispatch(self, request, *args, **kwargs):
if not request.session.get(‘user_info‘):
return redirect(‘/login.html‘)
ret = super(IndexView, self).dispatch(request, *args, **kwargs)
return ret
def get(self, request):
return render(request, ‘index.html‘)