zoukankan      html  css  js  c++  java
  • Flask学前之最小原型

    一、从selenium的原理讲起

    selenium操作游览器是需要webderiver驱动的,这个驱动其实就可以理解为服务器,selenium只是通过HTTP协议向webdriver发送请求,webdriver接收到请求后,在去驱动游览器做一些列的操作。

    我们打开双击运行webdriver.exe,然后通过游览器访问本地localhost:port,是可以访问通的。其实webdriver此时就开启了一个web服务

    而我们运行falsk或者django也是开启一个服务。和webdriver其实是大同小异的。

    from selenium import webdriver
    import requests
    import time
    
    url = "http://www.baidu.com"
    
    driver = webdriver.Chrome(port=7005)
    # driver.get(url)
    """
    get方法做了哪些事情,游览器是怎么打开了百度呢?
    通过源码可以看到执行了一个Command.GET,参数是我们传的url
    1、self.execute(Command.GET, {'url': url})
    Command.GET: 就是以POST的方式向webdriver发起请求
    Command.GET:('POST', '/session/$sessionId/url') 请求方法POST和地址localhost:7005
    {'url': url}: 参数
    
    """
    # 利用http协议与webdriver交互,实现驱动游览器访问百度
    requests.post(url=f"http://localhost:7005/session/{driver.session_id}/url", json={'url': url})
    time.sleep(2)
    driver.close()
    driver.quit()
    

    二、make_server实现简易的基于WSGI服务的server

    本次分享先抛开falsk,用python内置的wsgiref库实现的一个简易服务器。其实flask内置的服务原理也是这一套东西,这些都是本地我们本地调试时,开启的服务,实际生产环境我需要用uwsgi,ngnix等。

    1、最小简易服务器实现步骤

    • 创建一个WSGI服务器:make_server(host,port,app)
    • 处理程序app方法实现:app(env,start_response)构造url 响应对象
    • 运行服务器:serve_forever() 监听动作

    2、make_server(host,port,app)

    • host:ip地址,传空字符串默认localhost
    • port:端口
    • app:应用程序(application),需要定义url,构造响应对象,定义返回值。
      • env:app 与服务器如何通信的呢,其实就是通过环境变量environment,前端传输信息都会保存在里面
      • start_response: 响应对象,定义接口响应状态码,定义响应头信息
      • return:返回值到前端

    3、案例:可以通游览器访问调试

    from wsgiref.simple_server import make_server
    
    
    def app(env, start_response):
        """
        application 应用程序
        :param env: 环境变量
        :param start_response: 响应结果,需要构造
        :return:
        """
        # 定义首页,url从边境变量里取,字段:PATH_INFO
        if env.get("PATH_INFO") == "/":
            # 构造响应对象
            start_response("200 ok", [("content-type", "text/plain")])
            return [b"hello index page"]
        elif env.get("PATH_INFO") == "/home":
            start_response("200 ok", [("content-type", "text/plain")])
            return [b"hello home page"]
        else:
            start_response("404 not found", [("content-type", "text/plain")])
            return [b"not found page"]
    
    
    if __name__ == '__main__':
        # 创建server
        server = make_server('', 8005, app)
        # 永久开启
        server.serve_forever()
    
    

    4、注意:

    1、 status_code 必须是一个字符串,不能是200的数字,且要4位以上

    2、header 是一个元素构成的列表,不能字典

    3、返回值是一个列表且要是byte类型,encode

    5、如何确认服务器-application交互是通过环境变量的传输信息的

    我们只要断点debug调试即可,或者打印env查看

    • 包括本地环境变量信息
    • 包括前端请求服务器的数据都会保存环境里
      • ip、port、接口地址、host
      • 请求方法
      • 请求参数
      • 请求头
      • 以及本地配置的环境变量信息

    'REMOTE_HOST' = {str} ''
    'CONTENT_LENGTH' = {str} ''
    'SCRIPT_NAME' = {str} ''
    'SERVER_PROTOCOL' = {str} 'HTTP/1.1'
    'SERVER_SOFTWARE' = {str} 'WSGIServer/0.2'
    'REQUEST_METHOD' = {str} 'GET'
    'PATH_INFO' = {str} '/home'
    'QUERY_STRING' = {str} ''
    'REMOTE_ADDR' = {str} '127.0.0.1'
    'CONTENT_TYPE' = {str} 'text/plain'
    'HTTP_HOST' = {str} 'localhost:8005'
    'HTTP_CONNECTION' = {str} 'keep-alive'
    'HTTP_PRAGMA' = {str} 'no-cache'
    'HTTP_CACHE_CONTROL' = {str} 'no-cache'
    'SERVER_PORT' = {str} '8005'
    

    三、application优化

    当我们访问地址越来越多时,我们需要不断添加if,来判断,其他语言有switch语句,其实python有更强大的字典对象,以用映射的方法来处理,把url定义成key,响应对象单独写成方法,value对应方法名。

    此时,我们的app方法内,只需要url是不是在字典内,如果存在我们只需要调用对应的value,并返回值即可,如果不存在则直接返回定义的404的方法即可。

    这样就实现了集中管理,当我们在有新的url时,我们app方法内的逻辑是不需要维护的,我们只需要添加新url方法(构造响应结果,返回值),然后添加到字典内即可。

    而url和函数(构造响应对象、并返回值)组合起来就叫做路由

    其实flask中也有集中注册路由的机制,内部原理也时采用的这种映射原理,只不过flask准对中小型来说实现了更为方便装饰器,只需要把url通过装饰在视图函数上即可

    优化代码

    from wsgiref.simple_server import make_server
    
    
    # 函数实现
    def home(response):
        response("200 OK", [("content-type", "text/html")])
        return "<p style='color:red'>home</p>"
    
    
    def project(response):
        response("200 OK", [("content-type", "text/html")])
        return "<p style='color:red'>project</p>"
    
    
    def interface(response):
        response("200 OK", [("content-type", "text/html")])
        return "<p style='color:red'>interface</p>"
    
    
    def not_found(response):
        response("404 not found", [("content-type", "text/plain"), ("charset", "UTF-8")])
        return "page not found"
    
    
    # 建立映射关系
    route_path = {
        "/": home,
        "/project": project,
        "/project/interface": interface
    
    }
    
    
    def app(env, response):
        """
        application 应用程序,通过映射,app基本可以保持不变
        :param env: 环境变量
        :param response: 响应结果函数,需要构造
        :return:
        """
        url = env.get("PATH_INFO")
        # 先判断不存在
        if url is None or route_path.get(url) is None:
            # 直接调用not_found()方法,返回404
            return [not_found(response).encode()]
        # 存在,调用对应url key的函数被返回
        return [route_path.get(url)(response).encode()]
    
    
    if __name__ == '__main__':
        my_server = make_server('', 6005, app)
        my_server.serve_forever()
    
    

    四、总结

    1、app应用程序和服务器通信是通过环境变量

    2、app内必须需要构造响应对象

    3、 status_code 必须是一个字符串,不能是200的数字,且要4位以上

    4、header 是一个元素构成的列表,不能字典

    5、返回值是一个列表且要是byte类型,encode

    6、可以使用字典的方式保存映射关系,达到更好管理路由。

  • 相关阅读:
    Accept Xcode/iOS License to run git
    Public Key Retrieval is not allowed
    No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer
    HttpURLConnection调用Restful接口
    关于线程同步(7种同步方式)
    面试(初级)
    面试题(高级)
    RedisTemplate和StringRedisTemplate的区别 RedisTemplate几种序列化方式比较
    Redis 3.2.1集群 —— Redis-trib.rb工具详解(含原理)
    Redis 3.2.1集群 —— CLUSTER MEET ip port
  • 原文地址:https://www.cnblogs.com/jiangmingbai/p/13047454.html
Copyright © 2011-2022 走看看