• 二、Web框架实现


    一、简单web(socket)

    在前一篇WEB框架概述一文中已经详细了解了:从浏览器键入一个URL到返回HTML内容的整个过程。说到底,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

    最简单的Hello World程序如下:

    import socket
    
    HOST = ''
    PORT = 80
    listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listen_socket.bind((HOST, PORT))
    listen_socket.listen(1)
    connection, address = listen_socket.accept()
    request = connection.recv(1024)
    connection.sendall(b"""HTTP/1.1 200 OK
    Content-type: text/html
     
    <html>
        <body>
            <h1>Hello, World!</h1>
        </body>
    </html>""")
    connection.close()
    

     

    这个代码接收简单的连接和一个客户端单一的请求,不管请求的 URL 是什么,它都会响应 HTTP 200(所以,这并不是一个真正意义上的 web 服务器)。Content-type:text/html 行代码的是 header 字段,header 用来提供请求或者响应的元信息。

    我们从浏览器请求,可以得到如下结果:

    这就是最简单的WEB应用。

    如果要动态生成HTML,就需要把上述步骤自己来实现,每次定义发送和接受的内容。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是前面介绍过的WSGIWeb Server Gateway Interface。WSGI就是一种协议,描述web server(uwsgi)如何与web application(app)通信的规范。serverapplication的规范在PEP 3333中有具体描述。要实现WSGI协议,必须同时实现web server和web application,当前运行在WSGI协议之上的web框架有BottleFlaskDjango

    当然,在python中,我们可以通过WSGIref来演示一个WEB框架的实现过程。

    二、Web框架实现(Wsgiref)

    Wsgiref库我们在前面已经有详细认识,所以这里不再介绍。

    通过Wsgiref实现一个简单的WEB sever如下:

    from wsgiref.simple_server import make_server
    #1、符合WSGI规范的application
    def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [b'<h1>Hello, world!</h1>']
    
    #2、Wsgiref定义启动server httpd = make_server('', 80, application) print('Serving HTTP on port 80...')
    #3、开始监听HTTP请求: httpd.serve_forever()

      用户访问结果如下:

    我们从Wsgiref一文中了解到,environ其实是收集了一些环境变量(包括服务端的环境变量、客户端的请求信息以及wsgi信息),我们可以将其打印出来,添加代码:

    for k,v in environ.items():
    print k,v
    TMP C:UsersadminAppDataLocalTemp
    PYTHONIOENCODING UTF-8
    COMPUTERNAME ADMIN-PC
    wsgi.multiprocess False
    _OLD_VIRTUAL_PATH C:ProgramDataOracleJavajavapath;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;D:install softpython2.7
    USERDOMAIN admin-PC
    SERVER_PROTOCOL HTTP/1.1
    SERVER_SOFTWARE WSGIServer/0.1 Python/2.7.15
    PSMODULEPATH C:Windowssystem32WindowsPowerShellv1.0Modules
    SCRIPT_NAME 
    COMMONPROGRAMFILES C:Program FilesCommon Files
    PROCESSOR_IDENTIFIER Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
    REQUEST_METHOD GET
    PROGRAMFILES C:Program Files
    PROCESSOR_REVISION 3a09
    PATH C:ProgramDataOracleJavajavapath;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;D:install softpython2.7;D:xuequnvenvScripts
    QUERY_STRING 
    SYSTEMROOT C:Windows
    PYTHONUNBUFFERED 1
    PROGRAMFILES(X86) C:Program Files (x86)
    WINDOWS_TRACING_FLAGS 3
    CONTENT_LENGTH 
    HTTP_UPGRADE_INSECURE_REQUESTS 1
    VIRTUAL_ENV D:xuequnvenv
    HTTP_CACHE_CONTROL max-age=0
    HTTP_CONNECTION keep-alive
    TEMP C:UsersadminAppDataLocalTemp
    REMOTE_ADDR 127.0.0.1
    COMMONPROGRAMFILES(X86) C:Program Files (x86)Common Files
    PROCESSOR_ARCHITECTURE AMD64
    wsgi.url_scheme http
    ALLUSERSPROFILE C:ProgramData
    SERVER_PORT 80
    LOCALAPPDATA C:UsersadminAppDataLocal
    HOMEPATH Usersadmin
    PYCHARM_MATPLOTLIB_PORT 50538
    PROGRAMW6432 C:Program Files
    USERNAME admin
    HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    LOGONSERVER \ADMIN-PC
    PROMPT (venv) $P$G
    COMSPEC C:Windowssystem32cmd.exe
    PROGRAMDATA C:ProgramData
    PYTHONPATH D:install softpycharmPyCharm 2018.1.4helperspycharm_matplotlib_backend;D:xuequn
    wsgi.multithread True
    wsgi.input <socket._fileobject object at 0x0000000002900B10>
    HTTP_USER_AGENT Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
    HTTP_HOST localhost
    SESSIONNAME Console
    PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    PATH_INFO /
    FP_NO_HOST_CHECK NO
    WINDIR C:Windows
    wsgi.file_wrapper wsgiref.util.FileWrapper
    HTTP_ACCEPT_ENCODING gzip, deflate, br
    wsgi.version (1, 0)
    APPDATA C:UsersadminAppDataRoaming
    HOMEDRIVE C:
    SERVER_NAME admin-PC
    wsgi.run_once False
    REMOTE_HOST admin-PC
    SYSTEMDRIVE C:
    GATEWAY_INTERFACE CGI/1.1
    HTTP_ACCEPT_LANGUAGE zh-CN,zh;q=0.9,en;q=0.8
    PYCHARM_HOSTED 1
    NUMBER_OF_PROCESSORS 4
    _OLD_VIRTUAL_PROMPT $P$G
    PROCESSOR_LEVEL 6
    CONTENT_TYPE text/plain
    wsgi.errors <open file '<stderr>', mode 'w' at 0x0000000001D62150>
    COMMONPROGRAMW6432 C:Program FilesCommon Files
    OS Windows_NT
    PUBLIC C:UsersPublic
    USERPROFILE C:Usersadmin
    TMP C:UsersadminAppDataLocalTemp
    PYTHONIOENCODING UTF-8
    COMPUTERNAME ADMIN-PC
    wsgi.multiprocess False
    _OLD_VIRTUAL_PATH C:ProgramDataOracleJavajavapath;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;D:install softpython2.7
    HTTP_REFERER http://localhost/
    USERDOMAIN admin-PC
    SERVER_PROTOCOL HTTP/1.1
    SERVER_SOFTWARE WSGIServer/0.1 Python/2.7.15
    PSMODULEPATH C:Windowssystem32WindowsPowerShellv1.0Modules
    SCRIPT_NAME 
    COMMONPROGRAMFILES C:Program FilesCommon Files
    PROCESSOR_IDENTIFIER Intel64 Family 6 Model 58 Stepping 9, GenuineIntel
    REQUEST_METHOD GET
    PROGRAMFILES C:Program Files
    PROCESSOR_REVISION 3a09
    PATH C:ProgramDataOracleJavajavapath;C:Windowssystem32;C:Windows;C:WindowsSystem32Wbem;C:WindowsSystem32WindowsPowerShellv1.0;D:install softpython2.7;D:xuequnvenvScripts
    QUERY_STRING 
    SYSTEMROOT C:Windows
    PYTHONUNBUFFERED 1
    PROGRAMFILES(X86) C:Program Files (x86)
    WINDOWS_TRACING_FLAGS 3
    CONTENT_LENGTH 
    VIRTUAL_ENV D:xuequnvenv
    HTTP_CACHE_CONTROL no-cache
    HTTP_CONNECTION keep-alive
    TEMP C:UsersadminAppDataLocalTemp
    REMOTE_ADDR 127.0.0.1
    COMMONPROGRAMFILES(X86) C:Program Files (x86)Common Files
    PROCESSOR_ARCHITECTURE AMD64
    wsgi.url_scheme http
    ALLUSERSPROFILE C:ProgramData
    SERVER_PORT 80
    LOCALAPPDATA C:UsersadminAppDataLocal
    HOMEPATH Usersadmin
    PYCHARM_MATPLOTLIB_PORT 50538
    PROGRAMW6432 C:Program Files
    USERNAME admin
    HTTP_ACCEPT image/webp,image/apng,image/*,*/*;q=0.8
    LOGONSERVER \ADMIN-PC
    PROMPT (venv) $P$G
    COMSPEC C:Windowssystem32cmd.exe
    PROGRAMDATA C:ProgramData
    PYTHONPATH D:install softpycharmPyCharm 2018.1.4helperspycharm_matplotlib_backend;D:xuequn
    wsgi.multithread True
    wsgi.input <socket._fileobject object at 0x0000000002900B10>
    HTTP_USER_AGENT Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
    HTTP_HOST localhost
    SESSIONNAME Console
    PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
    PATH_INFO /favicon.ico
    FP_NO_HOST_CHECK NO
    WINDIR C:Windows
    wsgi.file_wrapper wsgiref.util.FileWrapper
    HTTP_ACCEPT_ENCODING gzip, deflate, br
    wsgi.version (1, 0)
    APPDATA C:UsersadminAppDataRoaming
    HOMEDRIVE C:
    SERVER_NAME admin-PC
    wsgi.run_once False
    REMOTE_HOST admin-PC
    SYSTEMDRIVE C:
    GATEWAY_INTERFACE CGI/1.1
    HTTP_ACCEPT_LANGUAGE zh-CN,zh;q=0.9,en;q=0.8
    PYCHARM_HOSTED 1
    NUMBER_OF_PROCESSORS 4
    _OLD_VIRTUAL_PROMPT $P$G
    PROCESSOR_LEVEL 6
    HTTP_PRAGMA no-cache
    CONTENT_TYPE text/plain
    wsgi.errors <open file '<stderr>', mode 'w' at 0x0000000001D62150>
    COMMONPROGRAMW6432 C:Program FilesCommon Files
    OS Windows_NT
    PUBLIC C:UsersPublic
    USERPROFILE C:Usersadmin
    

      

     以上是实现了一个简单的请求和响应的过程,但是每次请求都是响应的固定不变的内容(hello world!)。现实当中,我们肯定希望是动态的内容,而且一般是通过请求不同的URL来返回不同的HTML内容。

    所以,我们需要解决动态路由的问题。

    从上面的基本信息中我们可以找到一个非常有用的信息:PATH_INFO。其实,这个变量就是代表了当前请求的URL。返回的内容我们可以很容易解决,通过函数返回不同的HTML内容就可以了。

    #coding:utf-8
    from wsgiref.simple_server import make_server
    
    def user():
        return ['<h1>hello jay!</h1>']
    
    def test():
        return ['<h1>Just  a test</h1>']
    
    url_map = {'user':user,'test':test} #Flask里面就是通过url_map进行URL对象保存
    
    def application(environ, start_response):
        path=environ['PATH_INFO'].split('/')[1]
        start_response('200 OK', [('Content-Type', 'text/html')])
    
        if path in url_map: #这里比较LowB了,Flask里面会把URL和视图函数进行绑定。
            return url_map[path]()
        else:
            return ["<h1>Page 404,not found!</h1>".encode("utf8")]
    
    httpd = make_server('', 80, application)
    print('Serving HTTP on port 80...')
    # 开始监听HTTP请求:
    httpd.serve_forever()
    

      

      这样,我们就把用户通过不同URL访问的内容进行了不同的响应,效果如下:

     当然,如果是真实环境下,我们会从数据库中获取数据,把固定的内容替换成可变的HTML内容,这样一个简单的web框架就成型了,是不是So easy?

  • 相关阅读:
    使用序列化实现对象的拷贝
    理解 Java 的三大特性之多态
    LeetCode OJ:Add and Search Word
    关于Qt的事件循环以及QEventLoop的简单使用
    LeetCode OJ:Generate Parentheses(括号生成)
    LeetCode OJ:Maximal Square(最大矩形)
    LeetCode OJ:Range Sum Query 2D
    LeetCode OJ:Power of Two(2的幂)
    LeetCode OJ:Longest Increasing Subsequence(最长递增序列)
    LeetCode OJ:Ugly Number II(丑数II)
  • 原文地址:https://www.cnblogs.com/skyflask/p/9292101.html
Copyright © 2020-2023  润新知