zoukankan      html  css  js  c++  java
  • DIY一个web框架

    web框架

    Web框架(Web framework)是一种开发框架,用来支持动态网站、网络应用和网络服务的开发。这大多数的web框架提供了一套开发和部署网站的方式,也为web行为提供了一套通用的方法。web框架已经实现了很多功能,开发人员使用框架提供的方法并且完成自己的业务逻辑,就能快速开发web应用了。浏览器和服务器的是基于HTTP协议进行通信的。也可以说web框架就是在以上十几行代码基础张扩展出来的,有很多简单方便使用的方法,大大提高了开发的效率。

    wsgiref模块

    最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

    如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

    正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。而wsgiref模块就是python基于wsgi协议开发的服务模块。

    from wsgiref.simple_server import make_server
    
    
    def application(environ, start_response):
        # 按着http协议解析数据:environ---请求
        # 按着http协议组装数据:start_response---响应
        # print(environ)
        # print(type(environ))  # <class 'dict'>
        start_response("200 OK", [("Content-type", "text/html")])  # 这个格式是固定的,必须是这样(响应状态码, [(响应头), (响应头)...])
        # 得到请求路径
        path = environ.get("PATH_INFO")
        # 对请求路径进行判断
        if path == "/login":
            return [b"<h1>login</h1>"]  # 返回必须是列表类型
        elif path == "/index":
            return [b"<h1>index</h1>"]  # 返回必须是列表类型
        else:
            return [b"<h1>hello world</h1>"]  # 返回必须是列表类型
    
    
    # 封装socket
    httped = make_server("", 8090, application)
    
    # 等待用户连接:conn, addr = sock.accept()
    httped.serve_forever()  # 会调用application(environ, start_response)

    DIY一个web框架

     models.py

    # 在数据库生成用户表,在项目执行前只需运行一次即可,把所有创建数据表的操作都放在此文件即可
    import pymysql
    
    
    conn = pymysql.connect(
        host="127.0.0.1",
        port=3306,
        user="root",
        password="123456",
        db="web",
        autocommit=True
    )
    
    cur = conn.cursor()
    
    sql = """
    create table user_info(
        id int primary key auto_increnment not null,
        name varchar(32) not null,
        pwd varchar(32) not null
    """
    
    cur.execute(sql)
    
    cur.close()
    conn.close()

    main.py

    from wsgiref.simple_server import make_server
    from urls import url_patterns
    
    
    def application(environ, start_response):
        start_response("200 OK", [("Content-type", "text/html")])
        print(environ.get("PATH_INFO"))
        # 客户端请求路径
        path = environ.get("PATH_INFO")
    
        # 方案1---直接针对路径做判断,然后写业务逻辑代码
        # if path == "/login":
        #     with open("login.html", "rb") as f:
        #         data = f.read()
        #     return [data]
        # elif path == "/index":
        #     with open("index.html", "rb") as f:
        #         data = f.read()
        #     return [data]
    
        # 方案2---将业务处理逻辑封装成函数,与路径一一匹配放在元组,然后用一个列表放置所有的元组
        # 这样就不用频繁的使用if判断,而且解耦后,如果想增加一个路径,只需要添加一个对应视图函数即可
        # 把url_patterns(路由分发)列表放在urls.py
        # 把视图函数放在views.py
        # 把所有html文件放在templates文件夹下
        func = None
        # 循环列表,取出路径和对应视图函数地址
        for p, f in url_patterns:
            # 如果浏览器请求路径正确,那么把路径对应的视图函数地址赋值给func
            if path == p:
                func = f
                break
        # 如果func不为空,那么执行func,并且把客户端请求信息作为参数,返回func执行后的结果给客户端,如果为空则返回错误信息
        if func:
            return [func(environ)]
        else:
            return [b"404 error"]
    
    
    httped = make_server("", 8080, application)
    
    httped.serve_forever()

    urls.py

    from views import *
    

    url_patterns
    = [ ("/login", login), ("/reg", reg), ("/auth", auth), ]

    views.py

    import pymysql
    from urllib.parse import parse_qs
    
    
    def login(environ):
        with open("templates/login.html", "rb") as f:
            data = f.read()
        return data
    
    
    def reg(environ):
        with open("templates/reg.html", "rb") as f:
            data = f.read()
        return data
    
    
    def auth(environ):
        """
        以下操作是wsgiref模块读取form表单提交的数据,比Django复杂,但比我们自己处理起来要简单很多了
        :param environ:
        :return:
        """
        try:
            request_body_size = int(environ.get("CONTENT_LENGTH", 0))
        except (ValueError):
            request_body_size = 0
    
        request_body = environ['wsgi.input'].read(request_body_size)
        data = parse_qs(request_body)
        user = data.get(b"user")[0].decode("utf8")
        pwd = data.get(b"pwd")[0].decode("utf8")
        print(user, pwd)
        # 操作数据库
        conn = pymysql.connect(
            host="127.0.0.1",
            port=3306,
            user="root",
            password="123456",
            db="web",
        )
        cur = conn.cursor()
        sql = "select * from user_info where name=%s and pwd=%s;"
        cur.execute(sql, (user, pwd))
        # 如果用户名密码正确,那么返回index页面,不正确返回错误信息
        if cur.fetchone():
            f = open("templates/index.html", "rb")
            data = f.read()
            return data
        else:
            return b"user or pwd is wrong"

    login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
        <link rel="icon" href="//www.jd.com/favicon.ico">
    </head>
    <body>
    <h3>登录页面</h3>
    <!--向auth路径提交form表单-->
    <form action="http://127.0.0.1:8080/auth" method="post">
        <p>
            姓名:
            <input type="text" name="user">
        </p>
        <p>
            密码:
            <input type="password" name="pwd">
        </p>
        <p>
            <input type="submit" value="提交">
        </p>
    </form>
    
    </body>
    </html>

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <link rel="icon" href="//www.jd.com/favicon.ico">
    </head>
    <body>
    <h1>首页</h1>
    <img src="https://img0.baidu.com/it/u=2641803730,2025967347&fm=26&fmt=auto" alt="">
    </body>
    </html>

    总结

    """
    web框架功能总结
      1. main.py:启动文件,封装了socket
      2. urls.py:路径与视图函数映射关系---url控制器
      3. views.py:视图函数,固定有一个形式参数environ(所有的请求信息都在这个参数里面,请求路径/请求方式/请求数据...)---视图函数
      4. templates文件夹:html文件---模板
      5. models:在项目启动前,在数据库中创建表结构---与数据库相关
    """
    while True: print('studying...')
  • 相关阅读:
    网益云——冲刺博客0
    网益云——软件工程之现场编程实战
    2020福州大学软件工程实践个人总结
    2020福州大学软件工程实践结对编程作业二
    福州大学软件工程实践个人编程作业
    2020软工第一次作业
    C. Present(二分 + 扫描线)
    P1287 盒子与球
    错排
    Codeforces 1323 D. Present (思维)
  • 原文地址:https://www.cnblogs.com/xuewei95/p/15535572.html
Copyright © 2011-2022 走看看