赞
踩
Sanic学习记录
为什么要学习sanic,因为它快,因为它对开发者很友好,因为他有完整的中文文档,因为它有活跃的社区。使用它可以快速开发一个webserver,也可以在社区找到很多解决方案。
# server.py
from sanic import Sanic
from sanic.response import text
app = Sanic('app')
@app.get('/')
async def index(request):
return text('hello word')
启动, sanic 自带了启动应用
sanic server.app
也可以使用asgi的启动
uvicorn server:app
app = Sanic('app') # 这里必须有一个参数,主要是用于获取上下文应用,类似flash中的current_app
app2 = Sanic.get_app('app') # 如果当前只有一个,参数可省略
app2 = Sanic.get_app('app2',force_create=True) # 如果app2 不存在,则创建
### Sanic.get_app('app') 在使用时会报错,找不到已创建的sanic对象,不知道是不是window的锅
# 方式一:对象属性赋值 app.config.DB_NAME = 'apdb' # 方式二:字典属性赋值 app.config['DB_USER'] = 'appUser' # 方式三:字典update db_setting = { 'DB_HOST':'localhost', 'DB_NAME':'appdb', 'DB_USER':'appuser' } app.config.update(db_setting) # 方式四:设置环境变量,并以SANIC_ 开头,sanic会自动识别,也可以自定义前缀 # SANIC_ 前缀的环境变量 export SANIC_MY_SETTING = './setting.py' print(app.config.MY_SETTING) # 自定义前缀 APP_ export APP_MY_SETTING = './setting.py' app = Sanic('app',load_env='APP_') # 方式五:从配置文件更新 app.update_config('./setting') app.update_config("${APP_MY_SETTING}") # 这里的变量是环境变量,不是SANIC_开头的 # 方式六:update_config 字典 或者 类 app.update_config({ "DB_HOST":"127.0.0.1"}) class MYConfig: A = 1 B = 2 app.update_config(MYConfig) # 类 app.update_config(MYConfig()) # 对象
app.db = Database() # 不推荐
app.ctx.db = Database() # 推荐
它既可以是一个普通函数,也可以是一个异步的函数。
一个api接口的一个请求方法对应一个函数,有几个方法注册几次路由
from sanic import Sanic
from sanic.response import text
app = Sanic('app')
@app.get('/')
async def index(request):
return text('这是get请求')
@app.post('/')
async def index_post(request):
return text('这是post请求')
一个api接口的不同请求方法对应一个类视图,路由只需要注册一次
from sanic import Sanic from sanic.response import text app = Sanic('app') from sanic.views import HTTPMethodView # 类视图 class IndexView(HTTPMethodView): async def get(self, request): return text('这是get请求') async def post(self,request): return text('这是post请求') # 路由注册 app.add_route(IndexView.as_view(), "/")
无论是函数视图还是类视图,都必须接收一个参数,接收的参数是Request对象,视图返回的对象都是HTTPResponse对象
所以,正常的写法应该是指定参数类型,就像这样
from sanic.response import HTTPResponse, text from sanic.request import Request from sanic.views import HTTPMethodView from sanic import Sanic app = Sanic('app') # 函数视图 @app.get('/') async def index(request:Request) -> HTTPResponse: return text('这是get请求') # 类视图 class IndexView(HTTPMethodView): async def get(self, request:Request) -> HTTPResponse: return text('这是get请求') app.add_route(IndexView.as_view(),'/idx')
实际上,默认的第一个参数类型就是Request,响应对象类型就是 HTTPResponse ,所以大多数时候,都是省略的
路由和视图是对应关系
添加路由的几种方式
# 方式一:函数视图使用装饰器,并指定请求方法 @app.route('/test', methods=["POST", "PUT"]) async def handler(request): return text('OK') # 方式二:根据请求方式添加装饰器 @app.get('/test') async def handler(request): return text('OK') # 还可以使用post,put,delete等等 # 方式三:注册路由 app.add_route( handler, # 如果是函数视图,直接填函数名,如果是类视图,填 类视图.as_view() '/test', methods=["POST", "PUT"], )
路径反解析
反解析 app.url_for(‘视图名’) 视图名由三部分组成(应用名称.蓝图名.函数名),其中函数名可以指定,只需要定义视图时传入name参数,就可以自定义名称
app.url_for("post_handler", post_id=5, arg_one="one", _anchor="anchor") # post_id是路径参数,如果有的话,arg_one 是查询参数,_anchor 是锚点 # '/posts/5?arg_one=one#anchor' # _external requires you to pass an argument _server or set SERVER_NAME in app.config if not url will be same as no _external app.url_for("post_handler", post_id=5, arg_one="one", _external=True) # _external 是绝对uri # '//server/posts/5?arg_one=one' # when specifying _scheme, _external must be True app.url_for("post_handler", post_id=5, arg_one="one", _scheme="http", _external=True) # _scheme 是协议 # 'http://server/posts/5?arg_one=one' # you can pass all special arguments at once app.url_for("post_handler", post_id=5, arg_one=["one", "two"], arg_two=2, _anchor="anchor", _scheme="http", _external=True, _server="another_server:8888") # _server 是执行ip和端口 # 'http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor'
重定向
重定向往往是和反解析一起使用的,反解析之后的结果传递给重定向就会返回反解析对应的API
@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):
...
静态路径
app.static("/static", "/path/to/directory")
第一个参数是静态文件所需要匹配的路由
第二个参数是渲染文件所在的文件(夹)路径
name参数,自定义的视图名称,可用于反解析
app.static("/static", "/path/to/directory") # 反解析 app.url_for( "static", name="static", filename="file.txt", ) # 结果 '/static/file.txt' # 带name参数的 app.static( "/user/uploads", "/path/to/uploads", name="uploads", ) # 反解析 app.url_for( "static", name="uploads", filename="image.png", ) # 结果 '/user/uploads/image.png'
实际上,默认的第一个参数类型就是Request,对象中存储了除路径参数意外的其他参数以及其他数据
@app.get('/index/<name:str>') # 当参数在路径中时,就是路径参数
async def indexname(request,name):
return text(name)
查询字符串通常用在get请求中,在浏览器中,请求路径后面的?name=alan&d=1 类似这样的都是查询参数
@app.get('/index',name='index') # api 接口名称,如果不填,默认是函数名
async def indexname(request):
request.args # 键值对的方式,及字典的方式
request.query_args # [(key,value),...]的方式
return text('哈哈哈')
除了路径参数和查询参数,其他的参数都被封装到了请求体参数中,都可以使用 request.body 进行访问
但是,body是二进制的字符串,需要转译,而对于文件,通过body接收到的内容并不是我们想要的
当前端是以json格式的数据传递 的,我们可以使用request.json接收,接收到的内容会被自动转成字典,方便使用
@app.get('/index',name='index') # api 接口名称,如果不填,默认是函数名
async def indexname(request):
request.json # 键值对的方式,及字典的方式
return empty()
当前端是以表单的形式传递的参数,一般使用request.form 接收,接收到的也是字典
当前端传递的是文件,后端使用 request.files 接收,接收到的也是字典
从请求头中解析到的 Token <token>
或者 Bearer <token>
将会被赋值给 request.token
。
普通请求头 request.headers 是特殊的字典,每个键对应的都是一个列表
request.headers["foo"],
request.headers.get("Foo"),
request.headers.getone("FOO")
# 以上获取到的都是第一个元素,键不区分大小写
request.headers.getall("fOo")
# 获取的结果是列表
list(request.headers.items())
# 获取所有的请求头
通过 request.cookies
获取
自定义上下文是为了应用程序和拓展插件而保留的,Sanic 本身并不使用它,最常用的是通过中间件给request对象添加参数,在视图中访问
可以在中间件处理中在request.ctx对象上自定义赋值,以便在访问视图时使用
当多个请求共享一个连接时,Sanic 将提供一个上下文对象来允许这些请求共享状态。
尚在实验阶段,未完善使用
# 类视图方法一:使用装饰器
from sanic.views import stream
class SimpleView(HTTPMethodView):
@stream
async def post(self, request):
result = ""
while True:
body = await request.stream.read()
if body is None:
break
result += body.decode("utf-8"
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。