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、模板语法、数据库组成了。

4、web框架请求-响应流程图

posted @ 2023-06-08 21:33  FirstReed  阅读(2)  评论(0编辑  收藏  举报