zoukankan      html  css  js  c++  java
  • Web框架

    Web框架本质

    所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,这样我们就可以自己实现Web框架了。

    import socket
    
    sk = socket.socket()
    sk.bind(("127.0.0.1", 80))
    sk.listen(5)
    
    
    while True:
        conn, addr = sk.accept()
        data = conn.recv(8096)
        conn.send(b"OK")
        conn.close()

    可以说Web服务本质上都是在这十几行代码基础上扩展出来的。这段代码就是它们的祖宗。

    用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定?

    所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。

    这个规则就是HTTP协议,以后浏览器发送请求信息也好,服务器回复响应信息也罢,都要按照这个规则来。HTTP协议主要规定了客户端和服务器之间的通信格式。

    响应头在浏览器的network窗口可以看到,我们看到的HTML页面内容就是响应体。本质上还是字符串,因为浏览器认识HTML,所以会渲染出页面。

    每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。HTTP响应的Header中有一个Conent-Type表明响应的内容格式。如text/html表示HTML网页。

    HTTP GET请求的格式:

    GET /path HTTP/1.1
    header1:v1
    
    header2:v2
    

    使用 分隔多个header

    HTTP POST请求格式:

    POST /path HTTP/1.1
    header1:v1
    
    header2:v2
    
    
    
    
    请求体...

    当遇到连续两个 时,表示Header部分结束了,后面的数据是Body。

    HTTP响应的格式:

    200 OK
    Header1:v1
    
    Header2:v2
    
    
    
    
    响应体...

    让我们的Web框架在给客户端回复响应的时候按照HTTP协议的规则加上响应头,这样我们就实现了一个正经的Web框架了。

    import socket
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('127.0.0.1', 8000))
    sock.listen(5)
    
    while True:
        conn, addr = sock.accept()
        data = conn.recv(8096)
        conn.send(b"HTTP/1.1 200 OK
    
    ")
        conn.send(b"OK")
        conn.close()

    上述通过socket来实现了其本质。

    对于真实开发中的python  web程序来说,一般分为两部分:服务器程序和应用程序。

    服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。

    应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的web框架,例如:Django、Flask、web.py等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。、

    这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架都不友好。

    这时候标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

    WSGI(Web Server Gateway Interface)。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

    from wsgiref.simple_server import make_server
    
    
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])  # 设置HTTP响应的状态码和头信息
        return [bytes("<h1>Hello world!</h1>", encoding="utf8"),]
    
    
    if __name__ == '__main__':
        httpd = make_server('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()

    让web服务根据用户请求的URL不同而返回不同的内容。

    from wsgiref.simple_server import make_server
    
    
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
        url = environ['PATH_INFO']  # 取到用户输入的url
        if url == "/index/":
            return [bytes("<h1>这是index页面</h1>", encoding="utf8"), ]
        elif url == "/home/":
            return [bytes("<h1>这是home页面</h1>", encoding="utf8"), ]
        else:
            return [bytes("404没有该页面", encoding="utf8"), ]
    
    
    if __name__ == '__main__':
        httpd = make_server('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()

    更简单的解决办法:

    from wsgiref.simple_server import make_server
    
    
    def index():
        return [bytes("<h1>这是index页面</h1>", encoding="utf8"), ]
    
    
    def home():
        return [bytes("<h1>这是home页面</h1>", encoding="utf8"), ]
    
    
    # 定义一个url和函数的对应关系
    URL_LIST = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
        url = environ['PATH_INFO']  # 取到用户输入的url
        func = None  # 将要执行的函数
        for i in URL_LIST:
            if i[0] == url:
                func = i[1]  # 去之前定义好的url列表里找url应该执行的函数
                break
        if func:  # 如果能找到要执行的函数
            return func()  # 返回函数的执行结果
        else:
            return [bytes("404没有该页面", encoding="utf8"), ]
    
    
    if __name__ == '__main__':
        httpd = make_server('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()

    返回给浏览器完事的HTML内容:

    from wsgiref.simple_server import make_server
    
    
    def index():
        with open("index.html", "rb") as f:
            data = f.read()
        return [data, ]
    
    
    def home():
        with open("home.html", "rb") as f:
            data = f.read()
        return [data, ]
    
    
    # 定义一个url和函数的对应关系
    URL_LIST = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
        url = environ['PATH_INFO']  # 取到用户输入的url
        func = None  # 将要执行的函数
        for i in URL_LIST:
            if i[0] == url:
                func = i[1]  # 去之前定义好的url列表里找url应该执行的函数
                break
        if func:  # 如果能找到要执行的函数
            return func()  # 返回函数的执行结果
        else:
            return [bytes("404没有该页面", encoding="utf8"), ]
    
    
    if __name__ == '__main__':
        httpd = make_server('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()

    动态的返回内容,写一个字符串,然后替换:

    from wsgiref.simple_server import make_server
    
    
    def index():
        with open("index.html", "rb") as f:
            data = f.read()
        import time
        time_str = str(time.time())
        data_str = str(data, encoding="utf8")
        data_str = data_str.replace("@@a@@", time_str)
        return [bytes(data_str, encoding="utf8"), ]
    
    
    def home():
        with open("home.html", "rb") as f:
            data = f.read()
        return [data, ]
    
    
    # 定义一个url和函数的对应关系
    URL_LIST = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
        url = environ['PATH_INFO']  # 取到用户输入的url
        func = None  # 将要执行的函数
        for i in URL_LIST:
            if i[0] == url:
                func = i[1]  # 去之前定义好的url列表里找url应该执行的函数
                break
        if func:  # 如果能找到要执行的函数
            return func()  # 返回函数的执行结果
        else:
            return [bytes("404没有该页面", encoding="utf8"), ]
    
    
    if __name__ == '__main__':
        httpd = make_server('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()

    这是一个简单的动态,完全可以从数据库中查询数据,然后去替换html中的对应内容,然后再发送给浏览器完成渲染。这个过程就相当于HTML模板渲染数据。本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。

    模板渲染工具:jinja2

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="x-ua-compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>Title</title>
    </head>
    <body>
        <h1>姓名:{{name}}</h1>
        <h1>爱好:</h1>
        <ul>
            {% for hobby in hobby_list %}
            <li>{{hobby}}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    index2.html文件

    使用jinja2渲染index2.html文件:

    from wsgiref.simple_server import make_server
    from jinja2 import Template
    
    
    def index():
        with open("index2.html", "r") as f:
            data = f.read()
        template = Template(data)  # 生成模板文件
        ret = template.render({"name": "Alex", "hobby_list": ["烫头", "泡吧"]})  # 把数据填充到模板里面
        return [bytes(ret, encoding="utf8"), ]
    
    
    def home():
        with open("home.html", "rb") as f:
            data = f.read()
        return [data, ]
    
    
    # 定义一个url和函数的对应关系
    URL_LIST = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
        url = environ['PATH_INFO']  # 取到用户输入的url
        func = None  # 将要执行的函数
        for i in URL_LIST:
            if i[0] == url:
                func = i[1]  # 去之前定义好的url列表里找url应该执行的函数
                break
        if func:  # 如果能找到要执行的函数
            return func()  # 返回函数的执行结果
        else:
            return [bytes("404没有该页面", encoding="utf8"), ]
    
    
    if __name__ == '__main__':
        httpd = make_server('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()

    从数据库中查询数据,使用pymysql连接数据库:

    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select name, age, department_id from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()

    测试的user表:

    CREATE TABLE user(
      id int auto_increment PRIMARY KEY,
      name CHAR(10) NOT NULL,
      hobby CHAR(20) NOT NULL
    )engine=innodb DEFAULT charset=UTF8;
  • 相关阅读:
    idea Ctrl+Alt+向下箭头 复制不起作用问题解决
    @Data 注解使用
    idea class类增加注释
    mysql 固定用户赋值数据库权限
    springboot logback 详细配置
    gitblit 增加ssh key
    uniapp内嵌H5页面和uniapp页面相互传值
    博客搬家
    反编译,java字节流 ,wirshark抓包,php转换中文
    charles 双向抓包
  • 原文地址:https://www.cnblogs.com/tsboy/p/8626090.html
Copyright © 2011-2022 走看看