python写web封装app_Python_Web_App_Day_1:编写Web App骨架

用到知识点:logging、asyncio、aiohttp模块(后续补充知识点)

1、logging(日志)模块

功能:

提供了标准的日志接口,记录程序日志,包含正常的程序访问日志、错误、警告等信息输出

可以存为各种格式的日志数据

日志分为:debug()、info()、warning()、error()、critical()5个级别(级别:DEBUG < INFO < WARNING < ERROR < CRITICAL)

importloggingprint(logging.DEBUG) #10

print(logging.INFO) #20

print(logging.WARNING) #30

print(logging.ERROR) #40

print(logging.CRITICAL) #50

默认输出只显示大于等于WARNING的日志

importlogging

logging.debug('debug message')

logging.info('info message')

logging.warning('warning message')

logging.error('error message')

logging.critical('critical message')"""输出:

WARNING:root:warning message

ERROR:root:error message

CRITICAL:root:critical message"""

通过logging.basicConfig()函数灵活配置日志级别,日志格式,输出位置

在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有:

filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。

filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。

format:指定handler使用的日志显示格式。

datefmt:指定日期时间格式。

level:设置rootlogger(后边会讲解具体概念)的日志级别

stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。

format参数中可能用到的格式化串:

%(name)s Logger的名字

%(levelno)s 数字形式的日志级别

%(levelname)s 文本形式的日志级别

%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有

%(filename)s 调用日志输出函数的模块的文件名

%(module)s 调用日志输出函数的模块名

%(funcName)s 调用日志输出函数的函数名

%(lineno)d 调用日志输出函数的语句所在的代码行

%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示

%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数

%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒

%(thread)d 线程ID。可能没有

%(threadName)s 线程名。可能没有

%(process)d 进程ID。可能没有

%(message)s用户输出的消息

importlogging

logging.basicConfig(level=logging.DEBUG,

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

datefmt='%a, %d %b %Y %H:%M:%S',

filename='test.log',

filemode='w')"""level=logging.DEBUG:修改默认输出级别为Debug

format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s':指定handler使用的日志显示格式。

%(asctime)s:字符串形式的当前时间

%(filename)s:调用日志输出函数的模块的文件名

[line:%(lineno)d]:调用日志输出函数的语句所在的代码行

%(levelname)s:文本形式的日志级别

%(message)s:用户输出的消息

datefmt='%a, %d %b %Y %H:%M:%S':设置日期格式

%a:星期

%d:日期

%b:月份

%Y:年

%H:%M:%S:时:分:秒

filename='test.log':设置日志输出文件

filemode='w':设置日志输出文件打开方式"""logging.debug('debug message')

logging.info('info message')

logging.warning('warning message')

logging.error('error message')

logging.critical('critical message')"""test.log文件内容:

Wed, 21 Jun 2017 16:54:30 test.py[line:12] DEBUG debug message

Wed, 21 Jun 2017 16:54:30 test.py[line:13] INFO info message

Wed, 21 Jun 2017 16:54:30 test.py[line:14] WARNING warning message

Wed, 21 Jun 2017 16:54:30 test.py[line:15] ERROR error message

Wed, 21 Jun 2017 16:54:30 test.py[line:16] CRITICAL critical message"""

2、asyncio(异步IO)模块

用协程实现生产消息者模型

其实next()和send()在一定意义上作用是相似的,区别是send()可以传递yield表达式的值进去,而next()只能传递None进去。因此c.next() 和 c.send(None) 作用是一样的。

第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有Python yield语句来接收这个值。

defconsumer():

r= ''

whileTrue:

n= yield r #跳出生成器,n没有定义

if notn:return

print('[CONSUMER] Consuming %s...' %n)

r= '200 OK'

defproduce(c):

c.send(None)#启动生成器,从生成器函数的第一行代码开始执行

n =0while n < 5:

n= n + 1

print('[PRODUCE] Producing %s....' %n)

r=c.send(n) #获取yield返回值print('[PRODUCE] Consumer return %s....' %r)

c.close()#关闭consumer,整个过程结束

c = consumer() #创建生成器对象

produce(c)"""输出:

[PRODUCE] Producing 1....

[CONSUMER] Consuming 1...

[PRODUCE] Consumer return 200 OK....

[PRODUCE] Producing 2....

[CONSUMER] Consuming 2...

[PRODUCE] Consumer return 200 OK....

[PRODUCE] Producing 3....

[CONSUMER] Consuming 3...

[PRODUCE] Consumer return 200 OK....

[PRODUCE] Producing 4....

[CONSUMER] Consuming 4...

[PRODUCE] Consumer return 200 OK....

[PRODUCE] Producing 5....

[CONSUMER] Consuming 5...

[PRODUCE] Consumer return 200 OK...."""

asyncio的编程模型就是一个消息循环,通过async关键字定义一个协程(coroutine),协程也是一种对象。

协程不能直接运行,需要把协程加入到事件循环(loop),由后者在适当的时候调用协程。

asyncio.get_event_loop方法可以创建一个事件循环,然后使用run_until_complete将协程注册到事件循环,并启动事件循环。

importasyncio

asyncdef hello(): #async定义一个协程

print('hello world!')#await用于挂起阻塞的异步调用接口。

#异步调用,把asyncio.sleep(1)看成是一个耗时1秒的IO操作

r = await asyncio.sleep(1)print('hello again!')#创建一个事件循环

loop =asyncio.get_event_loop()#将协程注册到事件循环,并启动事件循环

loop.run_until_complete(hello())#关闭事件循环

loop.close()

用task封装两个coroutine

importasyncioimportthreading

asyncdef hello(): #async定义一个协程

print('hello world! (%s)' %threading.current_thread())#await用于挂起阻塞的异步调用接口。

#异步调用,把asyncio.sleep(1)看成是一个耗时1秒的IO操作

r = await asyncio.sleep(1)print('hello again! (%s)' %threading.current_thread())#创建一个事件循环

loop =asyncio.get_event_loop()

tasks=[hello(), hello()]#将协程注册到事件循环,并启动事件循环

loop.run_until_complete(asyncio.wait(tasks))#关闭事件循环

loop.close()"""输出:

hello world! (<_mainthread started>)

hello world! (<_mainthread started>)

(间隔约1秒后再输出下面)

hello again! (<_mainthread started>)

hello again! (<_mainthread started>)"""

我们用asyncio的异步网络连接来获取sina、sohu和163的网站首页

importasyncio

asyncdef wget(host): #async定义一个协程

print('wget %s...' %host)

connect= asyncio.open_connection(host, 80)

reader, writer=await connect

header= 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' %host

writer.write(header.encode('utf-8'))#刷新底层传输的写缓冲区。也就是把需要发送出去的数据,从缓冲区发送出去

await writer.drain()whileTrue:

line=await reader.readline()if line == b'\r\n':break

print('%s header > %s' % (host, line.decode('utf-8').rstrip()))

writer.close()#创建一个事件循环

loop =asyncio.get_event_loop()

tasks= [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]#将协程注册到事件循环,并启动事件循环

loop.run_until_complete(asyncio.wait(tasks))#关闭事件循环

loop.close()"""输出:

wget www.sohu.com...

wget www.sina.com.cn...

wget www.163.com...

www.163.com header > HTTP/1.0 302 Moved Temporarily

www.163.com header > Server: Cdn Cache Server V2.0

www.163.com header > Date: Wed, 21 Jun 2017 11:13:32 GMT

www.163.com header > Content-Length: 0

www.163.com header > Location: http://www.163.com/special/0077jt/error_isp.html

www.163.com header > Connection: close

www.sina.com.cn header > HTTP/1.1 200 OK

www.sina.com.cn header > Server: nginx

www.sina.com.cn header > Date: Wed, 21 Jun 2017 11:12:45 GMT

www.sina.com.cn header > Content-Type: text/html

www.sina.com.cn header > Last-Modified: Wed, 21 Jun 2017 11:11:09 GMT

www.sina.com.cn header > Vary: Accept-Encoding

www.sina.com.cn header > Expires: Wed, 21 Jun 2017 11:13:45 GMT

www.sina.com.cn header > Cache-Control: max-age=60

www.sina.com.cn header > X-Powered-By: shci_v1.03

www.sina.com.cn header > Age: 47

www.sina.com.cn header > Content-Length: 597663

www.sina.com.cn header > X-Cache: HIT from cnc.tianjin.sinacache.91.nb.sinaedge.com

www.sina.com.cn header > Connection: close

www.sohu.com header > HTTP/1.1 200 OK

www.sohu.com header > Content-Type: text/html;charset=UTF-8

www.sohu.com header > Connection: close

www.sohu.com header > Server: nginx

www.sohu.com header > Date: Wed, 21 Jun 2017 11:13:27 GMT

www.sohu.com header > Cache-Control: max-age=60

www.sohu.com header > X-From-Sohu: X-SRC-Cached

www.sohu.com header > Content-Encoding: gzip

www.sohu.com header > FSS-Cache: HIT from 8212655.14766265.9212435

www.sohu.com header > FSS-Proxy: Powered by 2969695.4280425.3969395"""

3、asyncio可以实现单线程并发IO操作。

asyncio用在服务器端,例如Web服务器,由于HTTP连接就是IO操作,因此可以用单线程+coroutine实现多用户的高并发支持。

asyncio实现了TCP、UDP、SSL等协议,aiohttp则是基于asyncio实现的HTTP框架。

编写一个HTTP服务器,分别处理以下URL:

/ - 首页返回b'

Index

';

/hello/{name} - 根据URL参数返回文本hello, %s!

importasynciofrom aiohttp importweb

asyncdefindex(request):

await asyncio.sleep(0.5)return web.Response(body=b'

Index

', content_type='text/html')

asyncdefhello(request):

await asyncio.sleep(0.5)

text= '

hello, %s!

' %request.match_info['name']return web.Response(body=text.encode('utf-8'), content_type='text/html')

asyncdefinit(loop):

app= web.Application(loop=loop)

app.router.add_route('GET', '/', index)

app.router.add_route('GET', '/hello/{name}', hello)

srv= await loop.create_server(app.make_handler(), '127.0.0.1', 8500)print('Server started at http://127.0.0.1:8500...')returnsrv

loop=asyncio.get_event_loop()

loop.run_until_complete(init(loop))

loop.run_forever()

1、输入浏览器:

http://127.0.0.1:8500/hello/char

浏览器输出:

hello, char!

2、输入浏览器:

http://127.0.0.1:8500

浏览器输出:

Index!

"""app.py编写Web App骨架"""

import logging; logging.basicConfig(level=logging.INFO)importasynciofrom aiohttp importweb

asyncdefindex(request):"""响应函数"""

return web.Response(body=b'

Awesome

', content_type='text/html')

asyncdefinit(loop):"""Web App服务器初始化"""

#制作响应合集

app = web.Application(loop=loop)#把响应函数添加到响应函数集合

app.router.add_route(method='GET', path='/', handler=index)#创建服务器(连接网址、端口,绑定handler)

srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9000)

logging.info('server start at http://127.0.0.1:9000')returnsrv#创建事件

loop =asyncio.get_event_loop()#运行

loop.run_until_complete(init(loop))#服务器不关闭

loop.run_forever()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值