Django 学习前戏
1、Http协议
Http协议是一种用于在Web服务器和Web浏览器之间传输数据的应用层协议。
1.1 为什么要有HTTP协议?
一个Web服务端,可能面多个不同的Web客户端。如果要解决兼容性问题有两种方案,要么我的Web服务器兼容所有的开发语言。要么我制定一个标准,所有的Web客户端要和我进行交互,就必须遵循这一规则。显然第二种是比较明智的。类似的统一标准的技术还有sql,现在微信小程序、支付宝小程序等。都是制定标准。举个生活中的案例,以往咱们充手机话费、交电费、交水费需要去不同的app,使用体验很差,如果把这些东西都统一到一个平台,这将方便用户的使用体验。增加使用用户的群体。
1.2 Http协议有哪四大特性?
- 无状态(Stateless):HTTP协议是一种无状态协议,也就是说服务器不会存储任何关于客户端的信息以供将来使用。每次客户端向服务器发送请求时,服务器都会重新处理该请求,而且不会记住上一次请求的信息。(cookie session token...)
- 无连接:客户端和服务器之间每次请求-响应的交互完成后,他们所维护的连接就断开。这种特性使得服务器更加高效的处理大量并发请求。并节约网络资源的消耗。(长连接 webSocket Http协议的大补丁)
- 基于TCP/IP之上的作用于应用层:HTTP使用TCP协议作为其底层传输层协议,这保证了HTTP数据的可靠传输。TCP协议提供了包含错误检测和纠错功能的可靠数据传输机制,从而有效避免了数据损坏或丢失等问题。(3次握手、4次挥手)
- 基于请求--响应:客户端发起HTTP请求,并等待服务器的HTTP响应。服务器收到客户端的HTTP请求,并返回一个HTTP响应。
1.3 Http请求和响应的数据格式
-
请求格式:
请求首行(请求的方式,协议的版本……) GET / HTTP/1.1
请求头(一堆K,v键值对如 cookie等)
\r\n(换行)
请求体(真正的数据在这里,发送post请求的时候才有,如果是get请求不会有)
-
响应格式
响应首行
响应头
\r\n
响应体
1.4 响应状态码
- 1XX:服务端已经成功接收到了你的数据,正在处理,你可以基础提交其他数据
- 2XX:服务器成功响应(200请求成功)
- 3XX:重定向
- 4XX: 请求错误(404 请求资源不存在,403拒绝访问,没有权限)
- 5XX:服务器内部错误(500)
1.5 请求方式
- GET :(无副作用): 向服务器请求指定资源,对服务器的资源没有修改
- POST:(有副作用) : 向服务器提交数据,可以对服务器的资源进行添加、修改等操作。
以下只作为了解:
- PUT:向服务器传送更新资源,用于对服务器上的某个资源进行添加、创建操作等。
- DELETE:请求删除指定的资源。
- HEAD:只请求页面的首部,即获取HTTP头信息,用于在不获取资源的情况下获取资源的元数据。
- CONNECT:用于代理服务器与目标主机建立连接隧道,用于进行加密通信。
- OPTIONS:返回服务器对特定资源所支持的HTTP请求方法列表,客户端可以根据返回的结果来确定下一步采取什么样的操作。
- PATCH:对资源进行部分修改,只会使用请求中的部分数据进行资源的更新。
2、手撸Web框架代码
import socket
HOST='127.0.0.1'
PORT=8888
# 创建socket对象并且绑定端口
listen_socket=socket.socket()
listen_socket.bind((HOST,PORT))
# 设置最大连接池
listen_socket.listen(5)
print(f'Serving HTTP on port {PORT}……')
while True:
# 拿到连接的对象.接收客户端的请求,响应客户端
conn,addr=listen_socket.accept()
data=conn.recv(1024)
print(data)
'''
响应首行(协议/版本号)
HTTP/1.1
200 ok 响应状态码
响应头
\r\n
\r\n
响应体
~hello baby
'''
conn.send(b'HTTP/1.1 200 ok \r\n\r\n ~hello baby')
conn.close()
2.1 推导路由
response_hear=b'HTTP/1.1 200 ok \r\n\r\n '
while True:
conn,addr=listen_socket.accept()
data=conn.recv(1024)
print(data.decode("utf-8"))
# GET /xxx HTTP/1.1\r\n
url=data.decode('utf-8').split('\r\n')[0].split(' ')[1]
print(url)
conn.send(response_hear)
if url=='/login':
conn.send(b'~hello login')
elif url=='/index':
conn.send(b'~hello index')
else:
conn.send(b'\r\n\r\n ~hello baby')
conn.close()
2.2 类型转换
# encode()方法表示将字符串编码为指定的二进制格式
# decode()方法表示将二进制数据解码为指定的字符串格式
data=b'hello 123'
url=str(data,encoding='utf-8')
url=Byte(url,encoding='utf-8')
3、wsgiref模块
3.1上面需要手动写:
- scoket
- 处理http请求(路由路径截取、写响应体)
from wsgiref import simple_server
def run(request,response):
'''
:param request: 请求的数据
:param response: 响应的数据
:return: 返回给客户端的数据
'''
print(request) # 打印出来是个本机的环境变量+加请求数据 是个字典。
'''
{
……
'PATH_INFO': '/xoo'
……
}
'''
url=request.get('PATH_INFO')
response('200 ok', [])
if url=="/index":
return [b'hello index']
elif url=="/home":
return [b'hello home']
elif url=="/end":
return [b'hello end']
return [b'hello web']
if __name__=='__main__':
server=simple_server.make_server('127.0.0.1',8080,run)
server.serve_forever()
3.2如果对于多个url,难道我们要一直写if……else……
?
from wsgiref import simple_server
def index(request):
return 'hello index'
def home(request):
return 'hello home'
def end(request):
return 'hello end'
def error(request):
# template模板
with open(r'E:\SynologyDrive\SynologyDrive\Django复习\day01\手撸Web框架\template\error.html','r', encoding='utf8') as f:
return f.read()
urls={
('/index',index),
('/home',home),
('/end',end),
}
def run(request,response):
'''
:param request: 请求的数据
:param response: 响应的数据
:return: 返回给客户端的数据
'''
# print(request) # 打印出来是个本机的环境变量+加请求数据 是个字典。
'''
{
……
'PATH_INFO': '/xoo'
……
}
'''
func_name=None
url_name=request.get('PATH_INFO')
response('200 ok', [])
for url in urls:
if url[0]==url_name:
func_name=url[1]
break
if func_name:
res=func_name(request)
else:
res=error(request)
return [res.encode('utf8')]
if __name__=='__main__':
server=simple_server.make_server('127.0.0.1',8080,run)
server.serve_forever()
3.3 能否按照功拆分成不同的py文件或文件夹呢?
- view.py
def index(request):
return 'hello index'
def home(request):
return 'hello home'
def end(request):
return 'hello end'
def error(request):
# template模板
with open(r'E:\SynologyDrive\SynologyDrive\Django复习\day01\day01\template\error.html','r', encoding='utf8') as f:
return f.read()
- urls.py
from view import *
urls_path={
('/index',index),
('/home',home),
('/end',end)
}
- server.py
from wsgiref import simple_server
from view import error
from urls import urls_path
def run(request,response):
func_name=None
url_name=request.get('PATH_INFO')
response('200 ok', [])
for url in urls_path:
if url[0]==url_name:
func_name=url[1]
break
if func_name:
res=func_name(request)
else:
res=error(request)
return [res.encode('utf8')]
if __name__=='__main__':
server=simple_server.make_server('127.0.0.1',8080,run)
server.serve_forever()
-
templates
存放html文件
-
static
存在静态资源。
以后只需要,views添加视图后后,只需要在url中添加一条元组就可以了。
3.4 要在当前网页上显示当前的系统时间
3.4.1 读取html文件,并且替换关键字
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>展示时间</h1>
<span>random_str</span>
</body>
</html>
def showtime(request):
c_time=time.strftime('%Y-%m-%d %X')
with open (r'E:\SynologyDrive\SynologyDrive\Django复习\day01\day01\template\showtime.html','r',encoding='utf8') as f:
data=f.read()
#字符串替换
new_data=data.replace('random_str',c_time)
return new_data
3.4.2 使用模板语法 jinja2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>展示时间</h1>
<span>{{random_str}}</span>
</body>
</html>
def showtime(request):
c_time=time.strftime('%Y-%m-%d %X')
with open (r'E:\SynologyDrive\SynologyDrive\Django复习\day01\day01\template\showtime.html','r',encoding='utf8') as f:
data=f.read()
#字符串替换
# new_data=data.replace('random_str',c_time)
temp_obj=Template(data)
res=temp_obj.render({'random_str':c_time})
return res
后端可以按照字典的方式传递参数过来,前端也可以按照后端的语法将数据拿出来。
from jinja2 import Template
def get_dict(request):
user_dict = {'name': 'jason', 'pwd': 123, 'hobby': 'read'}
new_list = [11, 22, 33, 44, 55, 66]
with open(r'templates/get_dict.html', 'r', encoding='utf8') as f:
data = f.read()
temp_obj = Template(data)
res = temp_obj.render({'user':user_dict,'new_list':new_list})
return res
<h1>字典数据展示</h1>
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user['pwd'] }}</p>
<p>{{ user.get('hobby') }}</p>
<h1>列表数据展示</h1>
<p>
{% for i in new_list%}
<span>元素:{{ i }}</span>
{% endfor %}
</p>
Django的组成也推导至此了。现在我们知道由wsgiref、路由、视图、template、模板语法、数据库组成了。