sanic入门(一)

sanic入门

说在前面的话

1、有Flask的基础学习该模块会很容易上手

2、该web框架基于python的asyncio异步模块,需要对该模块提前了解

一、快速开始

1、创建一个最简单的web应用main.py

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)

2、运行

python3 main.py

3、查看浏览器

浏览器打开 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语法定义,因为它们是异步函数。

1、路由带参数

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))

2、HTTP请求类型

默认情况下,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))

3、统一添加路由

# 先定义处理函数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'])

4、重定向url_for

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)]

5、websocket

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对象。

1、纯文本Plain Text

from sanic import response


@app.route('/text')
def handle_request(request):
    return response.text('Hello world!')

2、HTML

from sanic import response


@app.route('/html')
def handle_request(request):
    return response.html('

Hello world!

'
)

3、JSON

from sanic import response


@app.route('/json')
def handle_request(request):
    return response.json({'message': 'Hello world!'})

4、文件File

from sanic import response


@app.route('/file')
async def handle_request(request):
    return await response.file('/srv/www/whatever.png')

5、流,Streaming

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.

6、文件流File Streaming

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')

7、重定向Redirect

from sanic import response


@app.route('/redirect')
def handle_request(request):
    return response.redirect('/json')

8、原始数据Raw

Response without encoding the body

from sanic import response


@app.route('/raw')
def handle_request(request):
    return response.raw(b'raw data')

9、空 Empty

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)

你可能感兴趣的:(web,sanic)