web框架学习

Posted 旧时光清风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web框架学习相关的知识,希望对你有一定的参考价值。

web框架学习

HTTP协议(超文本协议)

四大特性

基于TCP/IP之上作用于应用层

基于请求响应

发是请求,给是响应

无状态

不保存用户状态,连一次就给忘了

无连接

eg:one night love

数据格式

请求格式

请求首行(请求方式,协议版本等)
请求头(一大堆K:V键值对)
\\r\\n
请求头(真正的数据 发post请求的时候才有 如果get请求不会有)

响应格式

响应首行
响应头
\\r\\n
响应体

响应状态码

用特定的数字表示一些数据
​ 1xx:服务端已经接收到了你的数据 正在处理 你可以提交其他数据
​ 2xx:服务端成功响应(200请求成功)
​ 3xx:重定向
​ 4xx:请求错误(404 请求资源不存在 403 拒绝访问)
​ 5xx:(服务器内部错误(500))

请求方式

get请求

朝别人要数据

post请求

向别人提交数据(eg:用户登录)

纯手撸web框架

  • 手动书写socket
  • 手动处理http格式数据

简单c/s连接

#服务端
import socket
server = socket.socket()
server.bind((\'127.0.0.1\', 8081))
server.listen(5)
while True:
    conn,addr = server.accept()
    data = conn.recv(1024)
    conn.send(b\'HTTP/1.1 200 OK\\r\\n\\r\\n\')
    print(data)
    conn.send(b\'hello baby\')
    conn.close()

稍微复杂web框架

客户端请求什么,就返回什么,eg:客户端发送http://127.0.0.1:8081/index则服务器返回给客户端index

import socket
server = socket.socket()
server.bind((\'127.0.0.1\', 8081))
server.listen(5)
while True:
    conn,addr = server.accept()
    conn.send(b\'HTTP/1.1 200 OK\\r\\n\\r\\n\')
    data = conn.recv(1024)
    print(data)
    data = data.decode(\'utf8\')
    current_path = data.split(\'\\r\\n\')[0].split(\' \')[1]
    print(current_path)
    if current_path == \'/index\':
        conn.send(b\'index\')
        #服务端还可以打开html文件,将文件中的东西显示给客户端
        # with open(r\'index.html\', \'rb\') as f:   
        #     conn.send(f.read())
    else:
        conn.send(b\'404 error\')
    conn.close()

基于wsgiref

如果我不想写上面代码中的socket连接和里面的index等内容,客户端发送100个不同的请求,我也不能手撸100遍啊!那也太累了吧,所以我们就利用了wsgiref模块,帮我们操作起来更简单和方便,我们可以把在wsgiref.py中的必要代码写在相对应的文件内,以下是各个文件中要放的东西。
urls.py 路由与视图函数对象关系

views.py 放的是视图函数(处理业务逻辑的)

templates 模板文件夹(一堆html文件)
wsgiref.py文件

from wsgiref.simple_server import make_server
from urls import urls
from views import *


def run(env,response):
    """
    :param env: 请求相关的所有数据
    :param response: 响应相关的所有数据
    :return:
    """
    response(\'200 OK\',[])
    current_path = env.get(\'PATH_INFO\')  #env里面有 很多数据,我们筛选有用的数据就行
    # 先定义一个变量名 用来存储后续匹配到的函数名
    func = None
    # for循环 匹配后缀
    for url in urls:
        if current_path == url[0]:
            func = url[1]  # 一旦匹配成功 就将匹配到的函数名赋值给func变量
            break  # 主动结束匹配
    # 判断func是否有值
    if 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)
    # 实时监听该地址  只要有客户端来连接 统一交给run函数去处理
    server.serve_forever()  # 启动服务端,永远等着客户端来连接

urls.py

from views import *

urls = [
    (\'/index\',index),  #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
    (\'/login\',login),
    (\'/xxx\',xxx),
]

views.py

from urls import urls

def index(env):
    return \'index\'


def login(env):
    return \'login\'

def error(env):
    return \'404 error\'


def xxx(env):
    return \'xxx\'

客户端通过访问服务器获取字典

我们这里需要用到一个模块jinja2
我们需要先去下载这个模块from jinja2 import Template
具体了解jinja2请点击链接https://www.cnblogs.com/yanjiayi098-001/p/11701150.html
wsgiref.py文件

from wsgiref.simple_server import make_server
from urls import urls
from views import *


def run(env,response):
    """
    :param env: 请求相关的所有数据
    :param response: 响应相关的所有数据
    :return:
    """
    response(\'200 OK\',[])
    current_path = env.get(\'PATH_INFO\')  #env里面有 很多数据,我们筛选有用的数据就行
    # 先定义一个变量名 用来存储后续匹配到的函数名
    func = None
    # for循环 匹配后缀
    for url in urls:
        if current_path == url[0]:
            func = url[1]  # 一旦匹配成功 就将匹配到的函数名赋值给func变量
            break  # 主动结束匹配
    # 判断func是否有值
    if 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)
    # 实时监听该地址  只要有客户端来连接 统一交给run函数去处理
    server.serve_forever()  # 启动服务端,永远等着客户端来连接

urls.py

urls = [
    (\'/get_user\',get_user),  #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
    
]

views.py

def get_user(env):
    d = {\'name\':\'jason\',\'pwd\':\'123\',\'hobby\':[\'read\',\'running\',\'music\']}
    with open(r\'get_user.html\',\'r\',encoding=\'utf-8\') as f:
        data = f.read()
    temp = Template(data)   #将data数据传给这个temp,做处理
    res = temp.render(user=d)  # 将字典d传递给前端页面 页面上通过变量名user就能够获取到该字典
    return res

get_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
#jinja2模块,可以对字典 进行以下取值,同时这是jinja变量取值 {{ }}的语法
<p>{{ user }}</p>
<p>{{ user.name }}</p>
<p>{{ user[\'pwd\'] }}</p>
<p>{{ user.get(\'hobby\') }}</p>
</body>
</html>

动静态页面

静态页面:就是一个写死的页面
动态页面:可以通过更改后端的数据,来反应到浏览器的页面上
​ eg:1.后端获取当前时间展示到前端
​ 2.后端获取数据库中的数据展示到前端

客户端通过访问服务器获取当前时间

那么如果用户访问服务端,则客户端页面就会显示当前时间,这样该怎么做呢?
我们要知道,页面就是要用到html,如果时间写在HTML,那么通过编码格式,他已经不再是时间了,那么怎样将时间显示在页面呢?
做法:我们要在wsgiref模块的基础上,先在html中写一串特定的字符,在后端将这串html和获取的时间作交换,具体看代码
wsgiref.py文件

from wsgiref.simple_server import make_server
from urls import urls
from views import *


def run(env,response):
    """
    :param env: 请求相关的所有数据
    :param response: 响应相关的所有数据
    :return:
    """
    response(\'200 OK\',[])
    current_path = env.get(\'PATH_INFO\')  #env里面有 很多数据,我们筛选有用的数据就行
    # 先定义一个变量名 用来存储后续匹配到的函数名
    func = None
    # for循环 匹配后缀
    for url in urls:
        if current_path == url[0]:
            func = url[1]  # 一旦匹配成功 就将匹配到的函数名赋值给func变量
            break  # 主动结束匹配
    # 判断func是否有值
    if 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)
    # 实时监听该地址  只要有客户端来连接 统一交给run函数去处理
    server.serve_forever()  # 启动服务端,永远等着客户端来连接

urls.py

from views import *

urls = [
    (\'/get_time\',get_time),  #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
    
]

views.py

from urls import *
from datetime import datetime


def get_time():
    current_time = datetime.now().strftime(\'%Y-%m-%d %X\')
    with open(r\'get_time.html\',\'r\',encoding=\'utf-8\') as f:    #这是一串字符串
        data= f.read()
    data = data.replace(\'$$time$$\',current_time)
    return data

get_time.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
$$time$$
</body>
</html>

客户端通过访问服务器获取数据库数据

获取数据库数据现在就和获取字典的方法差不多像了,只不过我们需要建一个数据库,通过链接数据库,去数据库里面拿值
wsgiref.py文件

from wsgiref.simple_server import make_server
from urls import urls
from views import *


def run(env,response):
    """
    :param env: 请求相关的所有数据
    :param response: 响应相关的所有数据
    :return:
    """
    response(\'200 OK\',[])
    current_path = env.get(\'PATH_INFO\')  #env里面有 很多数据,我们筛选有用的数据就行
    # 先定义一个变量名 用来存储后续匹配到的函数名
    func = None
    # for循环 匹配后缀
    for url in urls:
        if current_path == url[0]:
            func = url[1]  # 一旦匹配成功 就将匹配到的函数名赋值给func变量
            break  # 主动结束匹配
    # 判断func是否有值
    if 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)
    # 实时监听该地址  只要有客户端来连接 统一交给run函数去处理
    server.serve_forever()  # 启动服务端,永远等着客户端来连接

urls.py

urls = [
    (\'/get_db\',get_db),  #第二个是函数,如果匹配成功,就去views.py中去找相应的函数去运行
    
]

views.py

import pymysql

def get_db(env):
    conn = pymysql.connect(
        host = \'127.0.0.1\',
        port = 3306,
        user = \'root\',
        password = \'root\',
        database = \'day56\',
        charset = \'utf8\',
        autocommit = True
    )
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    sql = "select * from userinfo"
    cursor.execute(sql)  #提交sql语句,这个出发的是执行的对象并不是一个值
    res = cursor.fetchall()
    print(res)
    with open(r\'get_db.html\',\'r\',encoding=\'utf-8\') as f:
        data = f.read()
    temp = Template(data)
    ret = temp.render(user_list = res)  # 将字典d传递给前端页面 页面上通过变量名user就能够获取到该字典
    return ret

get_db.html
我们这里用到了bootstrap搭建页面,这就是一个典型的动态页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.3.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">用户列表</h1>
            <table class="table table-bordered table-striped table-hover">
                <thead>
                    <tr>
                        <th>id</th>
                        <th>name</th>
                        <th>pwd</th>
                    </tr>
                </thead>
                <tbody>
                    {% for user_dict in user_list %}
                        <tr>
                            <td>{{ user_dict.id }}</td>
                            <td>{{ user_dict.name }}</td>
                            <td>{{ user_dict.pwd }}</td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>

</div>
</body>
</html>

python三大主流web框架

A:socket部分

B:路由与视图函数对应关系

C:模板语法

Django Flask Tornado
大而全 自带的功能特别多 类似于航空母舰 有时候过于笨重 小而精 自带的功能特别少 类似于游骑兵第三方的模块特别多,如果将flask第三方模块全部加起来 完全可以超过django比较依赖于第三方模块 异步非阻塞 牛逼到可以开发游戏服务器
A用的别人的 wsgiref B自己写的 C自己写的 A用的别人的 werkzeug(基于wsgiref) B自己写的 C用的别人的 jinja2 三者全是自己写的

以上是关于web框架学习的主要内容,如果未能解决你的问题,请参考以下文章

ReactJs学习笔记01

PHP必用代码片段

text 来自Codyhouse框架的Browserlist片段源代码

JAVA WEB代码片段

web代码片段

python学习之路web框架