Python mini-web框架5:路由添加正则和log日志功能

一、给路由添加正则表达式

  • 给路由参数添加正则表达式的原因:在实际开发时,url中往往会带有很多的参数,例如:/add/0003.html 中0003 就是参数,如果没有正则的话,那么就需要编写 N@route 来进行添加 url 对应的函数到字典中,此时字典中的键值对有 N 个,浪费空间,而采用了正则的话,那么只要编写1@route 就可以完成多个 url 例如/add/0008.html/add/0003.html 等对同一个函数,此时的字典中键值对减少很多,如下示例代码

    import re
    from pymysql import connect
    
    # 定义一个空子典
    URL_FUNC_DICT = dict()
    
    
    def route(url):
            """
            带参数的装饰器来做路由
            :param url: 请求的url
            :return: 返回一个装饰器
            """
            def set_func(func):
                # 往空子典里面添加元素
                URL_FUNC_DICT[url] = func
    
                def call_func(*args, **kwargs):
                         return func(*args, **kwargs)
    
                return call_func
    
            return set_func
    
    
    @route(r"/add/(\d+)\.html")
    def add_focus(ret):
    
           # 1.获取股票代码
           stock_code = ret.group(1)
    
           # 2.判断下是否有这个股票代码
           # 创建Connection连接
           conn = connect(host='域名或者公网IP', port=3306, database='数据库名', user='用户名', password='密码',
                 charset='utf8')
           # 获得Cursor对象
           cursor = conn.cursor()
           sql = """select * from info where code=%s;"""
           cursor.execute(sql,(stock_code,))
    
           print("************-----------1------------------")
    
           # 如果要是没有这个股票代码,那么就认为是非法的请求
           if not cursor.fetchone():
                cursor.close()
                conn.close()
                return "没有这支股票,大哥 ,我们是创业公司,请手下留情..."
    
           print("************-----------2------------------")
    
           # 3.在股票存在的情况下查看股票是否关注过
           sql = """select * from focus as f inner join info as i on f.info_id = i.id where i.code=%s;"""
           cursor.execute(sql,(stock_code,))
           # 如果查出来表示关注过
           if cursor.fetchone():
                 cursor.close()
                 conn.close()
                 return "已经关注过了,请勿重复关注..."
    
           print("************-----------3------------------")
    
          # 4.在没有关注的情况下,进行关注,也就是往关注的信息表里面添加数据
          sql = """insert into focus (info_id) select id from info where code = %s;"""
          cursor.execute(sql,(stock_code,))
          conn.commit()
          cursor.close()
          conn.close()
    
          return "关注成功"
    
    
    def application(evn, start_reponse):
            start_reponse('200 OK', [('Content-Type', 'text/html;charset=utf-8')])
            file_name = evn['PATH_INFO']
            try:
                for url,func in URL_FUNC_DICT.items():
                       ret = re.match(url,file_name)
                       if ret:
                             return func(ret)
                       else:
                             return "请求的url(%s)没有对应的函数...." % file_name
    
            except Exception as ret:
                 return "产生了异常:%s"% str(ret)
    

二、url 编码

  • 2.1、python3对url编解码
    导入库 urllib.parse

    import urllib.parse
    

    Python3 url编码

    print(urllib.parse.quote("不忘初心,方得始终!"))
    打印结果:%E4%B8%8D%E5%BF%98%E5%88%9D%E5%BF%83%EF%BC%8C%E6%96%B9%E5%BE%97%E5%A7%8B%E7%BB%88%EF%BC%81
    

    Python3 url解码

    print(urllib.parse.unquote('%E4%B8%8D%E5%BF%98%E5%88%9D%E5%BF%83%EF%BC%8C%E6%96%B9%E5%BE%97%E5%A7%8B%E7%BB%88%EF%BC%81'))
    打印结果是:不忘初心,方得始终!
    

    完整的代码如下:

    import urllib.parse
    
    text = urllib.parse.quote("不忘初心,方得始终!")
    
    print("url编码后的文字=%s"%text)
    
    text = urllib.parse.unquote(text)
    
    print("url解码后的文字=%s"%text)
    
  • 2.2、浏览器往服务器传内容的时候会对内容进行编码,如果我们的框架在接收到消息后不进行解码直接写入数据库,我们服务器里面存的是url编码的内容,所以我们需要对内容进行解码,再存到数据库,这样下次读取出来的时候不再是url编码的内容

三、logging日志模块

  • 3.1、开发过程中出现bug是必不可免的,你会怎样debug?从第1行代码开始看么?还是有个文件里面记录着哪里错了更方便呢!!!log日志,Python中有个logging模块可以完成相关信息的记录,在debug时用它往往事半功倍

  • 3.2、日志级别:日志一共分成5个等级,从 低到高 分别是:

    DEBUG      # 调试模式
    INFO       # 确认一切按预期运行
    WARNING    # 警告
    ERROR      # 错误
    CRITICAL   # critical 英[ˈkrɪtɪkl]  严重的;
    

    解释:

    • DEBUG:详细的信息,通常只出现在诊断问题上
    • INFO:确认一切按预期运行
    • WARNING:一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如。磁盘空间低”)。这个软件还能按预期工作。
    • ERROR:更严重的问题,软件没能执行一些功能
    • CRITICAL:一个严重的错误,这表明程序本身可能无法继续运行
    • 总结:这5个等级,也分别对应5种打日志的方法: debug 、info 、warning 、error 、critical。默认的是WARNING,当在WARNING或之上时才被跟踪。
  • 3.3、日志输出
    有两种方式记录跟踪,一种输出控制台,另一种是记录到文件中,如日志文件。

    • (1)、将日志输出到控制台,比如,logTest.py 如下:

      import logging
      
      logging.basicConfig(level=logging.DEBUG,
                      format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
      # 开始使用log功能
      logging.debug('这是 loggging debug message')
      logging.info('这是 loggging info message')
      logging.warning('这是 loggging a warning message')
      logging.error("这是logging error message")
      logging.critical("这是logging critical message")
      

      打印结果如下:

      2019-01-17 10:00:53,331 - logTest.py[line:21] - DEBUG: 这是 loggging debug message
      2019-01-17 10:00:53,331 - logTest.py[line:22] - INFO: 这是 loggging info message
      2019-01-17 10:00:53,331 - logTest.py[line:23] - WARNING: 这是 loggging a warning message
      2019-01-17 10:00:53,331 - logTest.py[line:24] - ERROR: 这是logging error message
      2019-01-17 10:00:53,331 - logTest.py[line:25] - CRITICAL: 这是logging critical message
      
    • (2)、将日志输出到文件log.txt,比如,logTest2.py 如下:

      import logging
      
      
      """
         level:日志等级,5个等级,从小到大依次是:debug、info、warning、error、critical
         filename:要写入的日志文件名字
         filemode:日志写入的模式,a是追加日志信息 w是删除后添加新的日志信息
         format:格式,asctime 时间、filename 报错文件名、lineno 行数 、levelname 报错的等级、message 报错的信息
      """
      logging.basicConfig(level=logging.DEBUG,
                 filename='./log.txt',
                 filemode='a',
                 format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')
      
      # 开始使用log功能
      logging.debug('这是 loggging debug message')
      logging.info('这是 loggging info message')
      logging.warning('这是 loggging a warning message')
      logging.error("这是logging error message")
      logging.critical("这是logging critical message")
      

      运行后会生成一个 log.txt 文件

      Python mini-web框架5:路由添加正则和log日志功能_第1张图片
      运行后会生成一个 `log.txt` 文件

    • (3)、既要把日志输出到控制台, 还要写入日志文件
      这就需要一个叫作 Logger 的对象来帮忙,下面将对他进行详细介绍,现在这里先学习怎么实现把日志既要输出到控制台又要输出到文件的功能。

      import logging  
      
      # 第一步,创建一个logger  
      logger = logging.getLogger()  
      logger.setLevel(logging.DEBUG)  # Log等级总开关  
      
      # 第二步,创建一个handler,用于写入日志文件  
      logfile = './log.txt'  
      fh = logging.FileHandler(logfile, mode='a')  # open的打开模式这里可以进行参考
      fh.setLevel(logging.INFO)  # 输出到file的log等级的开关  
      
      # 第三步,再创建一个handler,用于输出到控制台  
      ch = logging.StreamHandler()  
      ch.setLevel(logging.WARNING)   # 输出到console的log等级的开关  
      
      # 第四步,定义handler的输出格式  
      formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")  
      fh.setFormatter(formatter)  
      ch.setFormatter(formatter)  
      
      # 第五步,将logger添加到handler里面  
      logger.addHandler(fh)  
      logger.addHandler(ch)  
      
      # 日志  
      logger.debug('这是 logger debug message')  
      logger.info('这是 logger info message')  
      logger.warning('这是 logger warning message')  
      logger.error('这是 logger error message')  
      logger.critical('这是 logger critical message')
      

      运行时终端的输出结果:

      2019-01-17 11:21:01,785 - logTest3.py[line:28] - WARNING: 这是 logger warning message
      2019-01-17 11:21:01,785 - logTest3.py[line:29] - ERROR: 这是 logger error message
      2019-01-17 11:21:01,785 - logTest3.py[line:30] - CRITICAL: 这是 logger critical message
      

      log.txt 中,有如下数据:

      2019-01-17 11:21:01,784 - logTest3.py[line:27] - INFO: 这是 logger info message
      2019-01-17 11:21:01,785 - logTest3.py[line:28] - WARNING: 这是 logger warning message
      2019-01-17 11:21:01,785 - logTest3.py[line:29] - ERROR: 这是 logger error message
      2019-01-17 11:21:01,785 - logTest3.py[line:30] - CRITICAL: 这是 logger critical message
      
  • 3.4、日志格式说明

    • logging.basicConfig函数中,可以指定日志的输出格式format,这个参数可以输出很多有用的信息,如下:

      %(levelno)s: 打印日志级别的数值
      %(levelname)s: 打印日志级别名称
      %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
      %(filename)s: 打印当前执行程序名
      %(funcName)s: 打印日志的当前函数
      %(lineno)d: 打印日志的当前行号
      %(asctime)s: 打印日志的时间
      %(thread)d: 打印线程ID
      %(threadName)s: 打印线程名称
      %(process)d: 打印进程ID
      %(message)s: 打印日志信息
      
    • 在工作中给的常用格式如下:

      format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'
      

      这个格式可以输出日志的打印时间,是哪个模块输出的,输出的日志级别是什么,以及输入的日志内容。

你可能感兴趣的:(Python mini-web框架5:路由添加正则和log日志功能)