# 라우팅(Routing)
지금까지 우리는 이 데코레이터를 다양한 형태로 많이 보았습니다.
그러나 이것은 뭘까요? 어떻게 사용할까요?
@app.route("/stairway")
...
@app.get("/to")
...
@app.post("/heaven")
...
# 라우터 추가 하기(Adding a route)
핸들러를 엔드포인트에 연결하는 가장 기본적인 방법은 app.add_route()
를 사용하는 것입니다.
자세한 내용은 API 문서 (opens new window)를 참조하세요.
async def handler(request):
return text("OK")
app.add_route(handler, "/test")
기본적으로 경로는 HTTP 'GET' 호출로 사용할 수 있습니다. 하나 이상의 HTTP 메서드에 응답하도록 핸들러를 변경할 수 있습니다.
app.add_route(
handler,
'/test',
methods=["POST", "PUT"],
)
HTTP 메소드(HTTP methods)
@app.route('/test', methods=["POST", "PUT"])
async def handler(request):
return text('OK')
# HTTP methods
각 표준 HTTP 메소드에는 편리한 데코레이터가 있습니다.
# 경로 매개 변수(Path parameters)
Sanic은 패턴 일치를 허용하고 URL 경로에서 값을 추출 할 수 있습니다. 그런 다음 이러한 매개 변수는 경로 처리기에서 키워드 인수로 삽입됩니다.
@app.get("/tag/<tag>")
async def tag_handler(request, tag):
return text("Tag - {}".format(tag))
매개 변수의 유형을 선언 할 수 있습니다. 일치 할 때 적용되며 변수를 형변환합니다.
@app.get("/foo/<foo_id:uuid>")
async def uuid_handler(request, foo_id: UUID):
return text("UUID - {}".format(foo_id))
# 지원되는 타입들(Supported types)
# 정규식 일치(Regex Matching)
복잡한 라우팅에 비해 위의 예는 너무 단순하고 완전히 다른 라우팅 일치 패턴을 사용하므로 여기서는 정규식 일치의 고급 사용법에 대해 자세히 설명합니다.
때로는 경로의 일부를 일치시키고 싶을 때가 있습니다.
/image/123456789.jpg
파일 패턴을 일치시키고 싶지만 숫자 부분만 캡처하려면 정규식을 재미있게 해야 합니다 😄:
app.route(r"/image/<img_id:(?P<img_id>\d+)\.jpg>")
또한 다음 사항이 모두 허용되어야 합니다.
@app.get(r"/<foo:[a-z]{3}.txt>") # matching on the full pattern
@app.get(r"/<foo:([a-z]{3}).txt>") # defining a single matching group
@app.get(r"/<foo:(?P<foo>[a-z]{3}).txt>") # defining a single named matching group
@app.get(r"/<foo:(?P<foo>[a-z]{3}).(?:txt)>") # defining a single named matching group, with one or more non-matching groups
또한 명명된 일치 그룹을 사용하는 경우 세그먼트 레이블과 동일해야 합니다.
@app.get(r"/<foo:(?P<foo>\d+).jpg>") # OK
@app.get(r"/<foo:(?P<bar>\d+).jpg>") # NOT OK
보다 일반적인 사용 방법은 정규식 연산 (opens new window)을 참조하세요.
# URL 생성(Generating a URL)
Sanic은 핸들러 메소드 이름: app.url_for ()
를 기반으로 URL을 생성하는 메소드를 제공합니다. 이는 앱에 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):
...
임의의 수의 키워드 인수를 전달할 수 있습니다. 요청 매개 변수가 아닌 모든 것은 쿼리 문자열의 일부로 구현됩니다.
>>> app.url_for(
"post_handler",
post_id=5,
arg_one="one",
arg_two="two",
)
'/posts/5?arg_one=one&arg_two=two'
또한 단일 쿼리 키에 대해 여러 값을 전달하는 것도 지원됩니다.
>>> app.url_for(
"post_handler",
post_id=5,
arg_one=["one", "two"],
)
'/posts/5?arg_one=one&arg_one=two'
# 특수 키워드 인수(Special keyword arguments)
자세한 내용은 API Docs를 참조하세요.
>>> app.url_for("post_handler", post_id=5, arg_one="one", _anchor="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)
'//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)
'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")
'http://another_server:8888/posts/5?arg_one=one&arg_one=two&arg_two=2#anchor'
# 사용자 지정 경로 이름 (Customizing a route name)
사용자 지정 경로 이름은 경로를 등록하는 동안 name
인수를 전달하여 사용할 수 있습니다.
@app.get("/get", name="get_handler")
def handler(request):
return text("OK")
이제 이 사용자 지정 이름을 사용하여 URL을 검색합니다.
>>> app.url_for("get_handler", foo="bar")
'/get?foo=bar'
# 웹소켓 경로 (Websockets routes)
Websocket 라우팅은 HTTP 메서드와 유사하게 작동합니다.
async def handler(request, ws):
messgage = "Start"
while True:
await ws.send(message)
message = ws.recv()
app.add_websocket_route(handler, "/test")
편리한 데코레이터도 있습니다.
@app.websocket("/test")
async def handler(request, ws):
messgage = "Start"
while True:
await ws.send(message)
message = ws.recv()
작동 방식에 대해 자세히 알아보려면 웹소켓 섹션을 읽어보세요.
# 엄격한 슬래시 (Strict slashes)
Sanic 경로는 후행 슬래시(/
)가 있는지 여부에 대해 엄격하게 일치하도록 구성할 수 있습니다. 이것은 몇 가지 수준에서 구성할 수 있으며 다음 우선 순위를 따릅니다.
- Route
- Blueprint
- BlueprintGroup
- Application
# provide default strict_slashes value for all routes
app = Sanic(__file__, strict_slashes=True)
# overwrite strict_slashes value for specific route
@app.get("/get", strict_slashes=False)
def handler(request):
return text("OK")
# it also works for blueprints
bp = Blueprint(__file__, strict_slashes=True)
@bp.get("/bp/get", strict_slashes=False)
def handler(request):
return text("OK")
bp1 = Blueprint(name="bp1", url_prefix="/bp1")
bp2 = Blueprint(
name="bp2",
url_prefix="/bp2",
strict_slashes=False,
)
# This will enforce strict slashes check on the routes
# under bp1 but ignore bp2 as that has an explicitly
# set the strict slashes check to false
group = Blueprint.group([bp1, bp2], strict_slashes=True)
# 정적 파일(Static files)
Sanic에서 정적 파일을 제공하려면, app.static()
을 사용하세요.
인자의 순서는 중요합니다:
- 파일이 제공될 경로
- 서버의 파일 경로
자세한 내용은 API Docs를 참고하세요.
app.static("/static", "/path/to/directory")
개별 파일을 제공할 수도 있습니다.
app.static("/", "/path/to/index.html")
때로는 엔드포인트의 이름을 지정하는 것이 도움이 됩니다.
app.static(
"/user/uploads",
"/path/to/uploads",
name="uploads",
)
URL 검색은 핸들러와 유사하게 작동합니다. 그러나 디렉토리 내부에 특정 파일이 필요할 때 filename
인수를 추가할 수도 있습니다.
>>> app.url_for(
"static",
name="static",
filename="file.txt",
)
'/static/file.txt'
```python
>>> app.url_for(
"static",
name="uploads",
filename="image.png",
)
'/user/uploads/image.png'
TIP
여러 static()
경로를 사용하려는 경우, 수동으로 이름을 지정하는 것이 매우 좋습니다. 이것은 버그를 발견하기 어려운 잠재적 가능성을 거의 확실히 완화할 것입니다.
app.static("/user/uploads", "/path/to/uploads", name="uploads")
app.static("/user/profile", "/path/to/profile", name="profile_pics")