sanic框架学习day2

目录

路由参数类型

动态访问

自定义路由名称(Customizing a route name)

静态文件(Static files)

路由上下文

中间件(请求中间件,响应中间件)

启用

变更

提前响应

请求头

响应头

cookies 

创建任务  add_task()


路由参数类型

字符串str

from sanic import Sanic

app = Sanic()
@app.route("/path/to/<foo:str>")
async def handler(request, foo:str):
    pass
使用正则表达式:r"[^/]+"
转换类型:str
匹配示例 /path/to/Hah; /path/to/Python%203

v22.3新strorempty

from sanic import Sanic

app = Sanic()

@app.route("/path/to/<foo:stroempty>")
async def handler(request, foo:str):
    pass

使用正则表达式: r"[^/]*")

转换类型: str

匹配示例:

/path/to/Bob
/path/to/Python%203
/path/to/
与 str 不同,strorempty 还能够匹配空字符串路径

整型int

from sanic import Sanic

app = Sanic()

@app.route("/path/to/<foo:int>")
async def handler(request, foo:int):
    pass 

使用正则表达式:r"-?\d+")
匹配例子
/path/to/10
/path/to/-10
无法匹配浮点型float, hex十六进制,octal八进制,etc

float 浮点型

@app.route("/path/to/<foo:float>")
async def handler(request, foo: float):
    ...
使用的正则表达式: r"-?(?:\d+(?:\.\d*)?|\.\d+)")

转换类型: float

匹配示例:

/path/to/10
/path/to/-10
/path/to/1.5
在之前版本中,您应该这样写 <foo:number>。这种写法将在 v21.12 中被弃用

alpha

@app.route("/path/to/<foo:alpha>")
async def handler(request, foo: str):
    ...
使用的正则表达式: r"[A-Za-z]+")

转换类型: str

匹配示例:

/path/to/Bob

/path/to/Python

无法匹配数字,空格以及其他特殊字符。

slug

在django中,slug指有效url的一部分,能使url更加清晰易懂,比如有这样一篇文章,标题是"13岁的孩子,它的URL地址是"/posts/13-sui-de-hai-zi",后面这一部分便是slug

@app.route("/path/to/<article:slug>")
async def handler(request, article: str):
    ...

使用的正则表达式: r"[a-z0-9]+(?:-[a-z0-9]+)*")

类型转换: str

匹配示例:

/path/to/some-news-story
/path/to/or-has-digits-123

path

@app.route("/path/to/<foo:path>")
async def handler(request, foo: str):
    ...
 
        Copied!
    
使用的正则表达式: r"[^/].*?")

转换类型: str

匹配示例:

/path/to/hello
/path/to/hello.txt
/path/to/hello/world.txt
注意

因为这将从 / 开始进行匹配,所以您应该小心使用,并测试您的正则表达式是否正确,以免匹配错误而调用了错误的响应函数。

ymd 年月日

@app.route("/path/to/<foo:ymd>")
async def handler(request, foo: datetime.date):
    ...

    
使用的正则表达式: r"^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))"

转换类型: datetime.date

匹配示例:

/path/to/2021-03-28

UUID

@app.route("/path/to/<foo:uuid>")
async def handler(request, foo: UUID):
    ...
 
       
    
使用的正则表达式: r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"

转换类型: UUID

匹配示例:

/path/to/123a123a-a12a-1a1a-a1a1-1a12a1a12345

regex

@app.route("/path/to/<foo:^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))>")
async def handler(request, foo: str):

    
使用的正则表达式: whatever you insert

转换类型: str

匹配示例:

/path/to/2021-01-01
该方法允许您使用自定义的匹配模式,在上面的示例中,我们通过指定的正则表达式,来匹配符合 YYYY-MM-DD 格式的路由参数。

ext

v22.3 新特征

@app.route("/path/to/<foo:ext>")
async def handler(request, foo: UUID):
    ...
 
        Copied!
    
使用的正则表达式: n/a

转换类型: varies

匹配示例:

定义	示例	文件名	拓展名
<file:ext>	page.txt	"page"	"txt"
<file:ext=jpg>	cat.jpg	"cat"	"jpg"
<file:ext=jpg|png|gif|svg>	cat.jpg	"cat"	"jpg"
<file=int:ext>	123.txt	123	"txt"
<file=int:ext=jpg|png|gif|svg>	123.svg	123	"svg"
<file=float:ext=tar.gz>	3.14.tar.gz	3.14	"tar.gz"
可以使用特殊的 ext 参数类型匹配文件扩展名。它使用一种特殊的格式,允许您指定其他类型的参数类型作为文件名,以及一个或多个特定的扩展名,如上表所示。

该方法 不 不支持 path 类型的参数。

动态访问

Sanic 提供了一种基于处理程序方法名生成 url 的方法:app.url_for(),您只需要函数名称即可实现响应函数之间的处理权力的移交。在您不希望将 url 进行硬编码或希望响应函数之间具有层级关系的时候,这将非常有用。它的使用方法如下:

@app.route('/')
async def index(request):
    # generate a URL for the endpoint `post_handler`
    url = app.url_for('post_handler', post_id=5)

    # Redirect to `/posts/5`
    return redirect(url)


@app.route('/posts/<post_id>')
async def post_handler(request, post_id):
    ...

自定义路由名称(Customizing a route name)

在注册路由的时候,可以通过给定 name 参数来自定义路由名称

@app.get("/get", name="get_handler")
def handler(request):
    return text("OK")

现在,您可以通过自定义的名称进行路由匹配。

>> > app.url_for("get_handler", foo="bar")
'/get?foo=bar'

静态文件(Static files)

为了确保 Sanic 可以正确代理静态文件,请使用 app.static() 方法进行路由分配。

在这里,参数的顺序十分重要

第一个参数是静态文件所需要匹配的路由

第二个参数是渲染文件所在的文件(夹)路径

app.static("/static", "/path/to/directory")
>> > app.url_for("get_handler", foo="bar")
'/get?foo=bar'

如果需要设置多个静态文件路由,我们需要手动为static()加上name参数,可以减少隐藏的Bug

app.static("/user/uploads", "/path/to/uploads", name="uploads")
app.static("/user/profile","/path/to/profile", name="profile_pics")

路由上下文

定义路由,可以添加任意数量的带有ctx_前缀的关键字参数,这些值会被注入到路由的ctx对象中 

@app.get("/1",ctx_label="something")
async def handler1(request):
     pass

@app.get("/2",ctx_label="something")
async def handler2(request):
     pass

@app.on_request
async def do_something(request):
    if request.route.ctx.label == "something":
        pass 

中间件(请求中间件,响应中间件)

启用

执行响应函数之前或者响应函数之后执行中间件,响应函数的构建,并将其挂载到 request 或 response 上

async def extract_user(request):
    request.ctx.user = await extract_user_from_request(request):
    
app.register_middleware(extract_user, "request")
  • 中间件使用装饰器挂载
app.MidderWare(requst)
async def test(request):
    request.ctx.user = await extract_user_from_request(request)

    
  • 响应中间件需要同时接收 request 和 response 两个参数
@app.middleware('response')
async def prevent_xss(request, response):
    response.headers["x-xss-protection"] = "1; mode=block"
  • 进一步缩短该装饰器的调用代码
@app.on_request
async def extract_user(request):
    ...

@app.on_response
async def prevent_xss(request, response):
    ...

变更

您的中间件 不涉及返回响应操作,那么您可以使用中间件来修改请求参数或者响应参数。

@app.middleware("request")
async def add_key(request):
    # Arbitrary data may be stored in request context:
    request.ctx.foo = "bar"


@app.middleware("response")
async def custom_banner(request, response):
    response.headers["Server"] = "Fake-Server"


@app.middleware("response")
async def prevent_xss(request, response):
    response.headers["x-xss-protection"] = "1; mode=block"


@app.get("/")
async def index(request):
    return text(request.ctx.foo)

您可以修改 request.match_info。这个功能可能很有用,比如下面这个例子中,在中间件里将 a-slug 改变为 a_slug

@app.on_request
def convert_slug_to_underscore(request: Request):
    request._match_info["slug"] = request._match_info["slug"].replace("-", "_")


@app.get("/<slug:[a-z0-9]+(?:-[a-z0-9]+)*>")
async def handler(request, slug):
    return text(slug)

提前响应

如果中间件返回一个HTTPR额搜谱暖色对象, 那么请求将会终止,此对象将会作为最终响应进行返回,如果这个操作发生在响应函数之前,那么响应函数也不会被调用,除此之外,此操作同样不会调用该中间件之后的其他中间件。您可以返回 None 值来跳过某个中间件的执行,如果这样的话将不影响后续中间件的执行。您可以将这个特性用于在提前响应中中间件的选择性执行。

请求头

@app.route("/")
async def test(request):
    return text(request.token)

request.token 可以获取身份令牌
request.host 属性来获取有效主机名
request.headers 可以获取真实的主机头信息
request.id  获取Id信息

有效的主机名称也可以与 request.url_for 方法一起使用,它可以确定响应函数所对应的外部地址。

app.config.SERVER_NAME = "https://example.com"

@app.route("/hosts", name="foo")
async def handler(request):
    return json(
        {
            "effective host": request.host,
            "host header": request.headers.get("host"),
            "forwarded host": request.forwarded.get("host"),
            "you are here": request.url_for("foo"),
        }
    )

您可以在请求对象的 request.headers 属性中获取所有的请求头,并且可以通过字典的方式来进行访问。Headers 的键名不考虑大小写,可以通过大写或小写键名来进行访问。

request.headers 对象是少数几个字典类型之一,每个值都是一个列表。这是因为HTTP允许重用一个键来发送多个值。

大多数情况下,您会希望使用 .get()或 .getone()方法访问第一个元素,而不是列表。如果您想要所有项目的列表,您可以使用 .getall() 方法。

响应头

  • content-length
  • content-type
  • connection
  • transfer-encoding

cookies 

1.读取,通过request.cookies.get("...")

from sanic import Sanic
from sanic.response import text

@app.route("/cookie")
async def test(request)
    test_cookie = request.cookies.get("test")
    return text("test cookie:{}".format(test_cookie)

2.设置.通过Response对象的response.cookies来设置cookies

@app.route("/cookie")
async def test(requst):
    response = text("there's a cookie up in this response")
    response.cookies['test'] = "hahah"
    return response
参数名称参数类型参数说明
expiresdatetimeCookie 在客户端浏览器上失效的时间。
pathstr此 Cookie 适用的 URL 子集。默认值为 /
commentstr注释(元数据)
domainstr指定 Cookie 的有效域。显式指定的域必须始终以点开始。
max-ageintCookie 应生存的秒数。
securebool指定是否仅通过 HTTPS 发送 Cookie。
httponlybool指定 Javascript 是否无法读取 Cookie。
samesitestr默认值取决于浏览器,规范状态(Lax、Strict 和 None)是有效值。

3.删除,通过del

@app.route("/cookie")
async def test(request):
    response = text("Time to eat some cookies muahaha")

    # 此 cookie 将被立即删除
    del response.cookies["kill_me"]

    # 此 cookie 将在 5 秒后删除
    response.cookies["short_life"] = "Glad to be here"
    response.cookies["short_life"]["max-age"] = 5
    
    del response.cookies["favorite_color"]

    # 此 cookie 将保持不变
    response.cookies["favorite_color"] = "blue"
    response.cookies["favorite_color"] = "pink"
    
    del response.cookies["favorite_color"]

    return response

创建任务  add_task()

async def slow_work(...):
   ...

app = Sanic(...)
app.add_task(slow_work) # Note: we are passing the callable and not coroutine object `slow_work(...)`
app.run(...)

python3.8以上版本还支持给任务重命名,

app.add_task(slow_work, name="slow_task")

 之后还可以可以使用 get_task 方法从应用程序的任何地方查看您的任务。

task = app.get_task("slow_task")

您想要取消任务,您可以通过 cacle_task 来进行操作,当然,该方法也是异步的,请确保使用时添加了 await

await app.cancel_task("slow_task")

所有注册的任务都可以在 app.tasks 属性中找到。为了防止已取消的任务填满,您可能需要运行 app.purge_tasks 来清除所有已完成或已取消的任务。 

app.purge_tasks()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值