Web Server Quickstart
1、Run a Simple Web Server(启动一个简单的Web服务器)
为了使一个web服务器生效,首先创建一个请求处理器
一个请求处理器必须是一个接受Request实例作为他唯一参数并且返回一个Response实例的协程:
from aiohttp import web
async def hello(request):
return web.Response(text="Hello, world")
之后,创建一个Application实例并在特定的HTTP方法和路径上注册请求处理器:
app = web.Application()
app.add_routes([web.get('/', hello)])
然后,通过 run_app() 运行(最好指定下端口,不然可能会有进程已经占用默认端口):
web.run_app(app,host='127.0.0.1', port=9000)
又或者你更愿意使用route装饰器创建一个route table 并注册一个web处理器:
routes = web.RouteTableDef()
@routes.get('/')
async def hello(request):
return web.Response(text="Hello, world")
app = web.Application()
app.add_routes(routes)
web.run_app(app)
两种方法本质上无区别,关键在于你喜欢上面的那种Django风格,还是下面的Flask风格
结果可以看到在127.0.0.1:9000上返回的hello world文本
2、Command Line Interface (CLI)(命令行界面)
aiohttp.web能够生效一个CLI给基于TCP/IP的程序快速提供给服务
$ python -m aiohttp.web -H localhost -P 8080 package.module:init_func
def init_func(argv):
app = web.Application()
app.router.add_get("/", index_handler)
return app
3、Handler(句柄)(ps:和第一节东西差不多)
一个句柄必须是一个接受Request实例作为他唯一参数并且返回一个 StreamResponse实例的协程:
async def handler(request):
return web.Response()
使用Application.add_routes()进行绑定:
app.add_routes([web.get('/', handler),
web.post('/post', post_handler),
web.put('/put', put_handler)])
或者使用route装饰器:
routes = web.RouteTableDef()
@routes.get('/')
async def get_handler(request):
...
@routes.post('/post')
async def post_handler(request):
...
@routes.put('/put')
async def put_handler(request):
...
app.add_routes(routes)
未知HTTP方法也是被 route() 或 RouteTableDef.route()支持的,允许一个Handler处理任何HTTP方法:
app.add_routes([web.route('*', '/path', all_handler)])
默认情况下,使用GET方法添加的端点将接受HEAD请求并返回与GET请求相同的响应头。你还可以拒绝路由上的HEAD请求:
web.get('/', handler, allow_head=False)
4、Resources and Routes(资源与路径)
内部路径由 Application.router (UrlDispatcher实例)提供。
路由器是一个资源列表。
资源是路由表中与请求的URL相对应的条目。
反过来,资源至少有一个路由。
Route对应于通过调用web handler来处理HTTP方法。
因此,当你添加路由时,resource对象将在底层创建。
库的实现合并同一路径的所有后续路由添加,为所有HTTP方法添加唯一的资源。
这儿有两个例子:
app.add_routes([web.get('/path1', get_1),
web.post('/path1', post_1),
web.get('/path2', get_2),
web.post('/path2', post_2)]
app.add_routes([web.get('/path1', get_1),
web.get('/path2', get_2),
web.post('/path2', post_2),
web.post('/path1', post_1)]
如果你认为第一个是更优化的,那么你就理解了。
(ps:加一下笔者的理解,第一种写法更能方便看出来不同路径方法的对应关系,防止重复被覆盖)
5、Variable Resources(可变资源)
资源也可以拥有可变路径,例如’/a/{name}/c’ 可以匹配’/a/b/c’, ‘/a/1/c’, and '/a/etc/c’等。
可变的部分类似这种形式{identifier},并且使用 Request.match_info进行匹配:
@routes.get('/{name}')
async def variable_handler(request):
return web.Response(
text="Hello, {}".format(request.match_info['name']))
默认情况下,每个部分都匹配正则表达式[^{}/]+。
当然也可以使用如下的方式:
web.get(r'/{name:\d+}', handler)
6、Reverse URL Constructing using Named Resources(使用命名资源实现URL反转)
路径可以用以下方式命名:
@routes.get('/root', name='root')
async def handler(request):
...
然后可以用来访问和构建该资源的URL:
url == request.app.router['root'].url_for().with_query({"a": "b", "c": "d"})
assert url == URL('/root?a=b&c=d')
一个更有趣的例子是构建可变资源的URL:
app.router.add_resource(r'/{user}/info', name='user-info')
在这种情况下,也可以传递部分路径:
url = request.app.router['user-info'].url_for(user='john_doe')
url_with_qs = url.with_query("a=b")
assert url_with_qs == '/john_doe/info?a=b'
7、Organizing Handlers in Classes(通过类的方法组织句柄)
正如上面所展示的,句柄可以使用第一类对象协程:
async def hello(request):
return web.Response(text="Hello, world")
app.router.add_get('/', hello)
但是开发者为了方便也可以自己编写一个:
class Handler:
def __init__(self):
pass
async def handle_intro(self, request):
return web.Response(text="Hello, world")
async def handle_greeting(self, request):
name = request.match_info.get('name', "Anonymous")
txt = "Hello, {}".format(name)
return web.Response(text=txt)
handler = Handler()
app.add_routes([web.get('/intro', handler.handle_intro),
web.get('/greet/{name}', handler.handle_greeting)]
to be modified