zoukankan      html  css  js  c++  java
  • Django 2.0 学习(15):Web框架

    Web框架的本质

    对于学习Python的同学,相信对Flask、Django、Web.py等不会陌生,这些都是Python语言的web框架。那么问题来了,web服务器是什么?它和web框架有什么关系?它们又是如何工作的?有的时候人们会把HTTP服务器叫做web服务器,这是为什么?我们今天就来聊聊这些,争取让大家对web开发有个清晰的认识。

    web服务器

    平时我们都是通过浏览器(Chrome、Firefox)来访问网站的,当我们在浏览器的地址栏输入地址后,会得到一个网页。这个网页就是web服务器返回给我们的,而浏览器就成为客户端,当我们输入网址并按下回车之后,就向web服务器发送了一个web请求。这种模式称为B/S模式,即Brower / Server模式,在浏览器地址栏输入地址按回车后,按下F12就可以看到如下信息:

    这整个过程如下图所示:

    • 建立连接:客户端通过TCP/IP协议建立到服务器的TCP连接;
    • 请求过程:客户端向服务器发送HTTP协议请求包(Request),请求服务器里的资源;
    • 应答过程:服务器向客户端发送HTTP协议应答包(Response),如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理"动态内容",并将处理的得到的数据返回给客户端。由客户端解释HTML文档,在客户端屏幕上渲染图形结果;
    • 关闭连接:客户机与服务器断开;

    这里Request和Response都需要遵守HTTP协议,关于HTTP协议的详细内容,并不在这里赘述。但是实际的web服务器远比上面的示例复杂的多,因为要考虑的因素实在太多了,比如:

    • 缓存机制:将某些经常被访问的页面缓存起来,提高响应速度;
    • 安全:防止黑客攻击,比如SYN Flood攻击;
    • 并发处理:如何响应不同客户端同时发起的请求;
    • 日志:记录访问日志,方便问题分析处理;

    目前在Linux和Unix平台下使用最广泛的免费web服务器有Apache和Nginx,而这些软件都是遵循HTPP协议的,所以也称为HTTP服务器,指示可以通过HTTP协议语言的解析转换。

    web应用程序

    web服务器接收Http Request,返回Response,很多时候Response并不是静态文件,因此需要有个应用程序根据Request生成相应的Response。这里的应用程序主要用来处理相关业务逻辑,读取或者更新数控,根据不同Request返回相应的Response。注意这里并不是web服务器本身来做这件事,它只负责Http协议层面和一些诸如并发处理、安全、日志等相关的事情。应用程序可以用各种语言编写(Java,PHP,Python,Ruby)等,这个应用程序会从web服务器接收客户端的请求,处理完成后,再返回响应给web服务器,最后由web服务器返回给客户端。整个架构如下所示:

    对于所有的web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端

    web框架(Framework)

    框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮助我们快速开发特定的系统,简单的说,就是利用别人搭建好的舞台来做表演。以Python web框架Flask为例,框架本身并不限制我们使用哪种架构来组织我们的应用,不过其中一种比较经典的web框架Flask采用了MVC架构,可以很好地支持以MVC方式组织应用:

    • 1.用户输入URL,客户端发送请求;
    • 2.控制器(Controller)首先拿到请求;
    • 3.然后用模型(Models)从数据库中取出所有需要的数据,进行必要的处理,将处理后的结果发送给视图(View);
    • 4.视图利用获取到的数据,进行渲染生成Html Response返回给客户端;

    具体如下图所示:

    还有一种同样热门且强大的web框架:Django,它的模式是MTV。Django的MTV模式本质是各组件之间为了保持松耦合关系,其MTV分别代表:

    • Model(模型):负责业务对象与数据库的对象(ORM);
    • Template(模板):负责如何把页面呈现给客户;
    • View(视图):负责业务逻辑,并在适当的时候调用Model和Template;

    此外,Django还有一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template。

    Web服务器网关接口

    我们知道Python有着许多的Web框架,而同时又有着许多的Web服务器(Apache,Nginx,Gunicorn等),框架和Web服务器之间需要进行通信,如果在设计时它们之间不可以相互匹配,那么选择了一个框架就会限制对Web服务器的选择,同样选择了Web服务器也会限制对Web框架的选择,这显然是不合理的。
    那么,怎样确保可以在不修改Web服务器代码或Web框架代码的前提下,使用自己选择的服务器,并且匹配多个不同的Web框架呢?答案是:接口,设计一套双方都遵守的接口就可以了。对Python来讲,就是WSGI(Web Server Gateway Interface,Web服务器网关接口)。其他编程语言也拥有类似的接口:例如Java的Serverlet API和Ruby的Rack。
    Python WSGI的出现,让开发者可以将Web框架与Web服务器的选择分隔开来,不再相互限制。现在我们可以真正地将不同的Web服务器与Web框架进行混合搭配,选择满足自己需求的组合。例如,可以使用Gunicorn或Nginx/uWSGI来运行Django、Flask或web.py应用。

    总结

    Web Server包括:

    • 提供Http服务的软件(Nginx);
    • Web应用程序在这个层面有许多Web框架Django、Flask、Tornado等;
    • 后端存储数据库Redis、MySQL等;

    自定义Web框架

    1.通过Python标准库提供的wsgiref模板开发一个自己的Web框架(Python3):

    from wsgiref.simple_server import make_server
    
    
    def index():
        return [bytes("<h2>index</h2>", encoding="utf-8"), ]
    
    
    def login():
        return [bytes("<h2>login</h2>", encoding="utf-8"), ]
    
    
    def routers():
        urlpatterns = (
            ("/index/", index),
            ("/login/", login),
        )
        return urlpatterns
    
    
    def run_server(environ, start_response):
        start_response("200 OK", [("Content-Type", "text/html")])
        url = environ["PATH_INFO"]
        urlpatterns = routers()
        func = None
        for item in urlpatterns:
            if item[0] == url:
                func = item[1]
                break
        if func:
            return func()
        else:
            return [bytes("<h1>404 not found</h1>", encoding="utf-8"), ]
    
    
    if __name__ == "__main__":
        httpd = make_server("", 8000, run_server)
        print("Servering HTTP on port 8000....")
        httpd.serve_forever()
    

    2.模板引擎
    在上步中,对于所有的login、index均返回给用户浏览器要给简单的字符串,在现实的Web请求中一般会返回一个复杂的符合HTML规则的字符串,所以我们一般将要返回给用户的HTML写在指定文件中,然后再返回。如:

    <!DOCTYPE html>         <!-- html文件声明开始 -->
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Index</title>
    </head>
    <body>
        <!-- index.html -->
        <h1>Index</h1>
    </body>
    </html>
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Login</title>
    </head>
    <body>
        <!-- login.html -->
        <form>
            <input type="text" />
            <input type="button" />
            <input type="submit" />
        </form>
    </body>
    </html>
    

    根据模板,将框架代码进行如下修改:

    from wsgiref.simple_server import make_server
    
    
    def index():
        # return [bytes("<h2>index</h2>", encoding="utf-8"), ]
        index = open("index.html")
        data = index.read()
        return data
    
    
    def login():
        # return [bytes("<h2>login</h2>", encoding="utf-8"), ]
        login = open("login.html")
        data = login.read()
        return data
    
    
    def routers():
        urlpatterns = (
            ("/index/", index),
            ("/login/", login),
        )
        return urlpatterns
    
    
    def run_server(environ, start_response):
        start_response("200 OK", [("Content-Type", "text/html")])
        url = environ["PATH_INFO"]
        urlpatterns = routers()
        func = None
        for item in urlpatterns:
            if item[0] == url:
                func = item[1]
                break
        if func:
            return func()
        else:
            return [bytes("<h1>404 not found</h1>", encoding="utf-8"), ]
    
    
    if __name__ == "__main__":
        httpd = make_server("", 8000, run_server)
        print("Servering HTTP on port 8000....")
        httpd.serve_forever()
    

    对于上述代码,虽然可以返回给用户HTML的内容以实现复杂的页面,但是还是存在问题:如何给用户动态内容?

    • 自定义一套特殊的语法,进行替换;
    • 使用开源工具Jinja2,遵循其指定语法;
    <!DOCTYPE html>         <!-- html文件声明开始 -->
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!-- 文件体 -->
        <h1>{{name}}</h1>
        <ul>
            {% for item in user_list %}
                <li>{{item}}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    
    from wsgiref.simple_server import make_server
    from jinja2 import Template
    
    
    def index():
        # return [bytes("<h2>index</h2>", encoding="utf-8"), ]
        index = open("index.html")
        data = index.read()
        template = Template(data)
        resutlt = template.render(name="Bob Gates", user_list=["eric", "rose"])
        return resutlt.encode("utf-8")
    
    
    def login():
        # return [bytes("<h2>login</h2>", encoding="utf-8"), ]
        login = open("login.html")
        data = login.read()
        return data
    
    
    def routers():
        urlpatterns = (
            ("/index/", index),
            ("/login/", login),
        )
        return urlpatterns
    
    
    def run_server(environ, start_response):
        start_response("200 OK", [("Content-Type", "text/html")])
        url = environ["PATH_INFO"]
        urlpatterns = routers()
        func = None
        for item in urlpatterns:
            if item[0] == url:
                func = item[1]
                break
        if func:
            return func()
        else:
            return [bytes("<h1>404 not found</h1>", encoding="utf-8"), ]
    
    
    if __name__ == "__main__":
        httpd = make_server("", 8000, run_server)
        print("Servering HTTP on port 8000....")
        httpd.serve_forever()
    

    遵循Jinja2的语法规则,其内部会对指定的语法进行相应的替换,从而达到动态的返回内容。

  • 相关阅读:
    Unity The Method Signature Matching Rule
    Unity The Property Matching Rule
    Unity The Type Matching Rule
    Unity The Custom Attribute Matching Rule
    Unity The Member Name Matching Rule
    Unity No Policies
    Unity The Return Type Matching Rule
    Unity The Parameter Type Matching Rule
    Unity The Namespace Matching Rule
    关于TSQL递归查询的(转)
  • 原文地址:https://www.cnblogs.com/love9527/p/9145019.html
Copyright © 2011-2022 走看看