0.web框架介绍

1. web应用概念

1.1 web应用
web --> 万维网简称.
web应用:通过web访问的程序.
能实现前后端的数据交互。
1.2 web开发架构
web软件开发架构:
1. C/S 架构  client  客户端 server 服务端
2. B/S 架构  browser 浏览器 server 服务端
   B/S的本质也是C/S,浏览器充当客户端.
服务器需要具备的特征: 24小时对外提供服务.
1.3 web框架的优/缺点
优点:
    1.只需要一个浏览器,不需要安装客户端.(B/S)
    2.客户端不需要更新,服务端更新即可.(B/S)
缺点:
	1.服务器出问题,客户端受到影响.
	2.网页兼容性问题

2.HTTP协议

HTTP协议四大特性:
1.基于请求响应
2.基于tcp/ip之上的应用层协议
3.无状态(不保存用户信息)
4./无链接。
数据请求格式:
    1.请求首行(http版本,
    2.请求头
    3./r/n
    4.请求体

响应数据格式:
    1.响应首行(状态码)
    2.响应头
    3./r/n
    4.响应体
http协议  数据传输是明文的 (在黑客眼里就是没穿衣服的小可爱)
https协议 数据传输是密文(数据更加的安全)
https = http + http + ssl(证书)
http  默认端口 80
https 默认端口 443
3.web服务端
自己写的服务端,打开浏览访问,是通过http协议通信的.需要send添加上HTTP协议.
响应头:
(b'HTTP/1.1 200 ok\r\n\r\n xxx信息)
HTTP/1.1 HTTP的版本 200 响应状态码 \r\n\r\n 响应体
# 服务端
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

while True:
    conn, addr = server.accept()
    data = conn.recv(1024)
    print(date)  
    conn.send(b'HTTP/1.1 200 ok\r\n\r\nhello word')
    conn.close()

image-20220228211410099

date重点研究对象(先省略掉 b'GET /favicon.ico)
客户端收到的get请求信息:
b'GET / HTTP/1.1\r\n
Host: 127.0.0.1:8080\r\n
Connection: keep-alive\r\n
Cache-Control: max-age=0\r\n
sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"\r\n
sec-ch-ua-mobile: ?0\r\n
Upgrade-Insecure-Requests: 1\r\n
...
Sec-Fetch-Site: none\r\n
Sec-Fetch-Mode: navigate\r\n
Sec-Fetch-User: ?1\r\n
Sec-Fetch-Dest: document\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6\r\n\r\n'
客户端收到的favicon.ico请求信息:
b'GET /favicon.ico HTTP/1.1\r\
...
favicon.ico请求处理:
favicon.ico 图标用于收藏夹图标和浏览器标签上的显示,如果不设置,
浏览器会请求网站根目录的这个图标,如果网站根目录也没有这图标会产生 404
出于优化的考虑,要么就有这个图标,要么就禁止产生这个请求。

不希望产生 favicon.ico 的请求。
可以在页面的 <head> 区域,加上如下代码实现屏蔽:

<link rel="icon" href="data:;base64,=">

或者详细一点
<link rel="icon" href="data:image/ico;base64,aWNv">

3.给客户端发信息

用户输入的后缀:127.0.0.1:8080/index/
依据后缀返回不同的结果.
思路:
0. 服务端获取的数据是二进制类型,转换为字符串类型。
1. 响应头返回的数据格式为 GET /index/ HTTP/1.1 ···
2. 这个数据以/进行切分,切分后是一个列表,index的索引为1
3. 判断 列表[1] 是否 = 'index'
# 服务端
import socket

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

while True:
    conn, addr = server.accept()
    data = conn.recv(1024)
    # 解码
    data = data.decode('utf-8')
    print(f'data 的数据>>>:{data}')

    # 对数据进行切分

    res = data.split('/')
    print(f'res[1] 的值>>>:{res[1]}')
    # 先发响应头再发 信息
    """
    http特性:当数据量比较小且时间间隔比较短的多次数据,
    那么TCP会自动打包成一个数据包发送.
    """
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')

    if res[1] == 'index':
        conn.send(b'index')
    else:
        conn.send(b'404')

image-20220228214353595

image-20220228215046249

4.返回前端页面

1.先创建一个my_html.html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>100G学习网址</title>
</head>
<body>
<a href="https://www.baidu.com">进入学习</a>
</body>
</html>
2.读取文件,b模式读取为二进制,直接将html文件二进制发给浏览器,浏览器会自动进行解析并渲染。
# 服务端
import socket

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

conn, addr = server.accept()
data = conn.recv(1024)

data = data.decode('utf-8')
conn.send(b'HTTP/1.1 200 ok\r\n\r\n')

with open('my_html.html', mode='rb') as rf:
    my_html = rf.read()
    conn.send(my_html)

image-20220228221510147

5.wsgiref模块

wsgiref是内置模块,内置一个服务端。
wsgiref模块只要作用
	1.请求来的时候解析http格式的数据 封装成大字典
	2.响应走的时候给数据打包成符合http格式 再返回给浏览器
from wsgiref.simple_server import make_server


def run(env, response):
    """
    :param env:      请求相关的所有数据
    :param response: 响应相关的所有数据
    :return:         返回浏览器的数据
    """
    print(env)  # env是一个字典,存放请求头内的所有数据
    response('200 ok', [])  # 响应状态码
    return [b'hello word']  # 返回页面的字符串


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)  # host, port, app 三个参数
    # 实时监听地址,只有接受到客户端的请求就交给run()处理,会将env, response两个函数的参数传给run函数
    print(type(server))  # <class 'wsgiref.simple_server.WSGIServer'>
    server.serve_forever()  # 启动服务端
启动服务端
在浏览器中输入: 127.0.0.1:8080/index
env 请求头是字典: 
{...一大堆数据···'PATH_INFO': '/index/'···}

image-20220228225154195

5.1给客户端返回信息1
依据后缀名称返回对应的值。
from wsgiref.simple_server import make_server


def run(env, response):
    # 请求头 格式是字典
    print(env)
    # 字典.get('PATH_INFO') 通过键 PATH_INFO 取到 url后面的 '路径' 信息
    path_info = env.get('PATH_INFO')

    response('200 ok', [])

    if path_info == '/index':
        return [b'index']
    elif path_info == '/login':
        return [b'login']
    else:
        return [b'404']


if __name__ == '__main__':
    # 绑定ip  端口 连接成功执行的函数
    server = make_server('127.0.0.1', 8080, run)  # host, port, app 三个参数
    # 实时监听地址,只有接受到客服的请求就交给run()处理,make_server有一个返回值
    # 会将env, response两个函数的参数传给run函数
    server.serve_forever()  # 启动服务端

image-20220228230339698

5.2给客户端返回信息2
依据后缀名称返回对应的值。
from wsgiref.simple_server import make_server


# 定义函数依据不同的值返回不同的信息
def index(env):
    return 'index'


def login(env):
    return 'login'


def error(env):
    return '404'


# 定义一个字典 存放所有函数
urls = [
    ('/index', index),
    ('/login', login)
]


def run(env, response):
    # 获取 url后面的 '路径'
    current_path = env.get('PATH_INFO')

    # 响应头
    response('200 ok', [])

    # 定义一个变量
    func = None

    # 遍历存放url的字典
    for url in urls:
        if current_path == url[0]:
            func = url[1]  # 将函数名作为值赋值给 func
            break  # 匹配之后立刻结束循环

    if func:  # 判断func是否为空, 只要不存在于url字典中,它的值就是None
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]  # 返回给客户端的值 是一个 列表套二进制字符串的格式


if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)
    server.serve_forever()

6.动/静态网页

静态网页:页面上的数据在html网页上写死的。

动态网页:数据是实时获取的。
    1.后端获取时间展示到html页面。
    2.数据是从数据库中获取到html页面。

7.web框架

将之前的一个文件拆分封装。
1.控制层 Control.py 写控制
2.路由层 urls.py 函数对应关系 依据url后面的'路径'返回不同的信息
3.视图层 views.ps 写逻辑
templates 文件夹 专门存储html前端页面


后续添加功能只需要在
urls.py 中书写对应的关系,
views.py 中书写业务逻辑。
# Control.py
from wsgiref.simple_server import make_server
from urls import *


def run(env, response):

    print(env)
    current_path = env.get('PATH_INFO')

    response('200 ok', [])
    # 定义一个变量
    func = None
    for url in urls:
        if current_path == url[0]:
            func = url[1]
            break  # 匹配之后立刻结束循环
    if func:  # 判断func是否为空
        res = func(env)
    else:
        res = error(env)
    return [res.encode('utf-8')]

if __name__ == '__main__':
    server = make_server('127.0.0.1', 8080, run)

    server.serve_forever()
# urls.py

from views import *

urls = [
    ('/index', index),
    ('/login', login),
    ('/study', study),
    ('/get_time', get_time)
]
# views.py

def index(env):
    return 'index'

def login(env):
    return 'login'

def error(env):
    return '404'

def study(env):
    with open('templates/myhtml.html', mode='rt', encoding='utf-8') as f:
        return f.read()

import datetime
def get_time(env):
    current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    with open('templates/my_time.html', mode='rt', encoding='utf-8') as f:
        date = f.read()    # 以字符串模式读入页面
        date = date.replace('xxx', current_time)   # 将字符串中xxx替换为时间
        return date
<!--   myhtml.html   templates 文件夹下 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>100G学习网址</title>
</head>
<body>
<a href="https://www.baidu.com">进入学习</a>
</body>
</html>
<!-- get_time.html   templates 文件夹下  动态网页 -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>time</title>
</head>
<body>
    xxx
</body>
</html>

8.模板语法

将一个字典传递给html文件,并可以在文件时上便捷的操作字典数据。
# 在urls.py中添加关系
('/get_dict', get_dict)
在templates文件下创建get_dir.html文件
模板语法是在后端起作用的
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>我是一个页面</h1>

    <!-- 模板语法 -->
    {{user }}
    {{user.get('username')}}
    {{user.age}}
    {{user['hobby']}}
</body>
</html>
# 在views.py中添加
# 安装 模板语法的Jinja2模块  pip3 install jinja2

from jinja2 import Template
def get_dict(env):
    user_div = {'username': 'kid', 'age': 18, 'hobby': 'read'}
    with open('templates/get_dic.html', mode='rt', encoding='utf-8') as f:
        data = f.read()

        tmp = Template(data)
        res = tmp.render(user=user_div)
        # 个头 get_dic.html传递一个值,页面上通过user就能够拿到use_dic
        return res
将html页面信息给Template处理,返回一个对象	
render方法修改html模板语法中对象的属性.
修改值的范式
obj.render(k='v') 
obj.render({'k': 'v'})

模板语法:
{{user }}                以字典展示  {'username': 'kid', 'age': 18, 'hobby': 'read'} 
{{user.get('username')}} 通过get取值  kid
{{user.age}}             通过.取值    18
{{user['hobby']}}        通过键取值   read

9.简易web框架

9.1目录结构

image-20220301144802267

目录结构:
项目:
	|----bin
	|    |-start.py 启动文件
	|
	|----core
	|    |-src.py   控制文件
	|
	|----url
	|    |-urls.py  函数对应关系
	|
	|----view
	|    |-views.py 业务逻辑
	|
	|----lib
	|    |-common.py 公共文件
	|
	|----conf
	|	|-setting.py 配置文件
	|
	|----templates  前端页面
		|-login.html
		|-index.html
		|-time.html
		|-get_dict.html
9.2启动文件
# start.py
import os
import sys
from core import src

# pycharm中会自动替我们完成下面两步.
# 1.获取当前项目路径
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
# print(BASE_PATH)
# F:/synchro/Project/web_frame

# 2.把 当前项目路径 添加到搜索模块路径当中
sys.path.append(BASE_PATH)
# print(sys.path)

# 启动程序
if __name__ == '__main__':
    src.run()
9.3控制文件
# src.py
# 核心控制

from wsgiref.simple_server import make_server
from url import urls


# 服务器 运行的 app 运行之后 服务器将 env, response 两个参数传给app
def web_app(env, response):
    print('2.收到请求,启动web_app!')

    # 获取请求头 --> 字典
    print(f'3.请求头信息{env}')

    # 获取url后面的路径 通过键取值
    get_url = env.get('PATH_INFO')
    print(f'4.客户输入的路径{get_url}')

    # 准备好可以访问的资源
    print('5.判断路径是否存在...')
    for url in urls.accessible:
        if get_url == url:
            msg = urls.accessible[get_url]()
            print('6.路径存在!')
            break
    else:
        print('6.路径不存在!')
        # 定义一个变量存放返回的信息
        msg = '404'

    print('7.发送响应通用')
    response('200 ok', [])
    print(f'8.发送响应体>>:\n {msg}')
    return [msg.encode('utf8')]


# 启动程序
def run():
    print('0.程序启动!')

    # 创建服务器对象 需要传入三个参数  ip    端口   app
    server = make_server('127.0.0.1', 8080, web_app)
    print('1.绑定信息成功! \n 开始监听...')

    # 0.5秒检查一次服务是否在启动
    server.serve_forever()
9.4函数对应关系
# urls.py
# 存储函数对应关系
from view import views

# 路由字典
accessible = {
    # 登入
    '/logon': views.login,
    # 目录索引
    '/index': views.index,
    # 获取时间
    '/time': views.time
}		
9.5业务逻辑
# views.py
# 业务逻辑

from conf import setting
from lib import common
import datetime


# 获取 login.html 的信息
def login():
    # 路径拼接 拿到 login.html 的路径
    login_html_path = setting.get_html_path('login.html')

    # 读取文件
    html_msg = common.get_html_msg(login_html_path)

    # 返回文件信息
    return html_msg


# 获取 index.html 的信息
def index():
    # 路径拼接 拿到 index.html 的路径
    index_html_path = setting.get_html_path('index.html')

    # 读取文件
    html_msg = common.get_html_msg(index_html_path)

    # 返回文件信息
    return html_msg


def time():
    # 路径拼接 拿到 time.html 的路径
    time_html_path = setting.get_html_path('time.html')

    html_msg = common.get_html_msg(time_html_path)
    # print(html_msg)

    # 获取当前时间
    new_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    # 将页面中的xxx 替换为当前时间
    html_msg = html_msg.replace('xxx', new_time)
    # 返回文件信息
    return html_msg
9.6公共文件
# common.py
# 读取网页信息
def get_html_msg(html_path):
    # 以二进制模式读取
    with open(html_path, mode='rt', encoding='utf8') as rf:
        # 返回 页面信息
        return rf.read()
9.7配置文件
# setting.py
# 获取 templates 路径. templates 存取前端页面
import os

# 获取项目的路径
BATH_PATH = os.path.dirname(os.path.dirname(__file__))

# 拼接 templates 的路径
templates_path = os.path.join(BATH_PATH, 'templates')


# 拼接 templates下的 html文件
def get_html_path(html_name):
    html_path = os.path.join(templates_path, html_name)
    return html_path
9.8前端页面
<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登入页面</title>
    <link rel="icon" href="data:image/ico;base64,aWNv">
</head>
<body>
    <h1>登入页面</h1>
</body>
</html>
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>目录索引</title>
    <link rel="icon" href="data:image/ico;base64,aWNv">
</head>
<body>
    <h1>目录索引</h1>
</body>
</html>
<!-- time.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>获取时间</title>
    <link rel="icon" href="data:image/ico;base64,aWNv">
</head>
<body>
    xxx
</body>
</html>	
<!-- get_dict.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法</title>
    <link rel="icon" href="data:image/ico;base64,aWNv">
</head>
<body>
    <h1>信息</h1>

    <!-- 模板语法 -->
    {{user }}
    {{user.get('username')}}
    {{user.age}}
    {{user['hobby']}}
</body>
</html>
在浏览器输入127.0.0.1:8080/get_dict
0.程序启动!
1.绑定信息成功! 
 开始监听...
 
2.收到请求,启动web_app! # 在这输入
3.请求头信息{...}
4.客户输入的路径/get_dict
5.判断路径是否存在...
127.0.0.1 - - [01/Mar/2022 15:34:19] "GET /get_dict HTTP/1.1" 200 308
<Template memory:23ec6971a90> <class 'jinja2.environment.Template'>
6.路径存在!
7.发送响应通用
8.发送响应体>>:
 <!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板语法</title>
    <link rel="icon" href="data:image/ico;base64,aWNv">
</head>
<body>
    <h1>信息</h1>

    <!-- 模板语法 -->
    {'username': 'kid', 'age': 18, 'hobby': 'read'}
    kid
    18
    read
</body>
</html>

image-20220301153401904

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值