1、有Flask的基础学习该模块会很容易上手
2、该web框架基于python的asyncio异步模块,需要对该模块提前了解
from sanic import Sanic # 提前自行下载该模块
from sanic.response import json
app = Sanic()
@app.route("/")
async def test(request):
return json({"hello": "world"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
python3 main.py
浏览器打开 0.0.0.0:8000,就成看到json格式的hello world
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQoAFl5N-1584971894667)(/Users/bobwang/Library/Application Support/typora-user-images/image-20200323093726836.png)]
路由允许用户为不同的URL端点指定处理程序功能。
from sanic.response import json
@app.route("/")
async def test(request):
return json({ "hello": "world" })
'''
当访问URL http://server.url/(服务器的基本URL)时,路由器将最后一个/与处理函数test匹配,然后返回JSON对象。
'''
Sanic处理程序函数必须使用async def语法定义,因为它们是异步函数。
Sanic带有支持请求参数的基本路由器。
要指定参数,请在其周围加上如下的引号:。请求参数将作为关键字参数传递给路由处理程序函数。
from sanic.response import text
@app.route('/tag/' )
async def tag_handler(request, tag):
return text('Tag - {}'.format(tag))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xWjD98gN-1584971894673)(/Users/bobwang/Library/Application Support/typora-user-images/截屏2020-03-23上午11.43.34.png)]
如果没有匹配上,则会返回如下信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LGw6toQK-1584971894676)(/Users/bobwang/Library/Application Support/typora-user-images/截屏2020-03-23上午11.44.28.png)]
string
“Bob”“Python 3”
int
102030-10(No floats work here)
number
11.510-10
alpha
“Bob”“Python”(If it contains a symbol or a non alphanumeric character it will fail)
path
“hello”“hello.text”“hello world”
uuid
123a123a-a12a-1a1a-a1a1-1a12a1a12345 (UUIDv4 Support)
正则表达式
如果未设置任何类型,则应为字符串。赋予函数的参数将始终是字符串,与类型无关。
@app.route('/string/' )
async def string_handler(request, string_arg):
return text('String - {}'.format(string_arg))
@app.route('/int/' )
async def integer_handler(request, integer_arg):
return text('Integer - {}'.format(integer_arg))
@app.route('/number/' )
async def number_handler(request, number_arg):
return text('Number - {}'.format(number_arg))
@app.route('/alpha/' )
async def number_handler(request, alpha_arg):
return text('Alpha - {}'.format(alpha_arg))
@app.route('/path/' )
async def number_handler(request, path_arg):
return text('Path - {}'.format(path_arg))
@app.route('/uuid/' )
async def number_handler(request, uuid_arg):
return text('Uuid - {}'.format(uuid_arg))
@app.route('/person/' )
async def person_handler(request, name):
return text('Person - {}'.format(name))
@app.route('/folder/' )
async def folder_handler(request, folder_id):
return text('Folder - {}'.format(folder_id))
默认情况下,URL上定义的路由仅可用于对该URL的GET请求。但是,@ app.route装饰器接受可选参数methods,该参数允许处理程序函数与列表中的任何HTTP方法一起使用。
@app.route('/post', methods=['POST'])
async def post_handler(request):
return text('POST request - {}'.format(request.json))
@app.route('/get', methods=['GET'])
async def get_handler(request):
return text('GET request - {}'.format(request.args))
Shorthand速记方法
@app.post('/post')
async def post_handler(request):
return text('POST request - {}'.format(request.json))
@app.get('/get')
async def get_handler(request):
return text('GET request - {}'.format(request.args))
限制host参数,非该host的其他ip将不能访问
@app.route('/get', methods=['GET'], host='example.com')
async def get_handler(request):
return text('GET request - {}'.format(request.args))
# 先定义处理函数Define the handler functions
async def handler1(request):
return text('OK')
async def handler2(request, name):
return text('Folder - {}'.format(name))
async def person_handler2(request, name):
return text('Person - {}'.format(name))
# Add each handler function as a route
app.add_route(handler1, '/test')
app.add_route(handler2, '/folder/' )
app.add_route(person_handler2, '/person/' , methods=['GET'])
from sanic.response import redirect
@app.route('/')
async def index(request):
# generate a URL for the endpoint `post_handler`
url = app.url_for('post_handler', post_id=5)
# the URL is `/posts/5`, redirect to it
return redirect(url)
@app.route('/posts/' )
async def post_handler(request, post_id):
return text('Post - {}'.format(post_id))
运行结果,会先302重定向
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZW0R5cWC-1584971894680)(/Users/bobwang/Library/Application Support/typora-user-images/image-20200323121217055.png)]
另外:
还可以在url_for中携带不是请求参数的关键字参数,并将其包含在URL的查询字符串中
url = app.url_for('post_handler', post_id=5, arg_one='one', arg_two='two')
# 等价于
/posts/5?arg_one=one&arg_two=two
# 参数获取
arg = request.args.get('arg_one')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4Xck1Pa0-1584971894689)(/Users/bobwang/Library/Application Support/typora-user-images/image-20200323121625820.png)]
from sanic import Sanic
from sanic.response import file
app = Sanic(__name__)
@app.route('/')
async def index(request):
return await file('websocket.html')
@app.websocket('/feed')
async def feed(request, ws):
while True:
data = 'hello!'
print('Sending: ' + data)
await ws.send(data)
data = await ws.recv()
print('Received: ' + data)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8000, debug=True)
html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebSocket demotitle>
head>
<body>
<script>
var ws = new WebSocket('ws://' + document.domain + ':' + location.port + '/feed'),
messages = document.createElement('ul');
ws.onmessage = function (event) {
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode('Received: ' + event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
window.setInterval(function() {
data = 'bye!'
ws.send(data);
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode('Sent: ' + data);
message.appendChild(content);
messages.appendChild(message);
}, 1000);
script>
body>
html>
当端点接收到HTTP请求时,将向路由功能传递一个 Request对象。
from sanic import response
@app.route('/text')
def handle_request(request):
return response.text('Hello world!')
from sanic import response
@app.route('/html')
def handle_request(request):
return response.html('Hello world!
')
from sanic import response
@app.route('/json')
def handle_request(request):
return response.json({'message': 'Hello world!'})
from sanic import response
@app.route('/file')
async def handle_request(request):
return await response.file('/srv/www/whatever.png')
from sanic import response
@app.route("/streaming")
async def index(request):
async def streaming_fn(response):
await response.write('foo')
await response.write('bar')
return response.stream(streaming_fn, content_type='text/plain')
See Streaming for more information.
For large files, a combination of File and Streaming above
from sanic import response
@app.route('/big_file.png')
async def handle_request(request):
return await response.file_stream('/srv/www/whatever.png')
from sanic import response
@app.route('/redirect')
def handle_request(request):
return response.redirect('/json')
Response without encoding the body
from sanic import response
@app.route('/raw')
def handle_request(request):
return response.raw(b'raw data')
For responding with an empty message as defined by RFC 2616
from sanic import response
@app.route('/empty')
async def handle_request(request):
return response.empty()
asyncio参看https://www.cnblogs.com/shenh/p/9090586.html
from sanic import Sanic
from sanic.response import json
import asyncio
import aiohttp
app = Sanic(__name__)
sem = None
@app.listener('before_server_start')
def init(sanic, loop):
global sem
concurrency_per_worker = 4
sem = asyncio.Semaphore(concurrency_per_worker, loop=loop) # 限制并发数,不超过linux默认的1024和windows默认的509
async def bounded_fetch(session, url):
"""
Use session object to perform 'get' request on url
"""
async with sem, session.get(url) as response:
return await response.json()
@app.route("/")
async def test(request):
"""
Download and serve example JSON
"""
url = "https://api.github.com/repos/channelcat/sanic"
async with aiohttp.ClientSession() as session:
response = await bounded_fetch(session, url)
return json(response)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8000, workers=2)