Skip to content

Instantly share code, notes, and snippets.

@allieus
Last active April 30, 2022 03:03
Show Gist options
  • Save allieus/01cdd091906f0f3653d57275aa70f288 to your computer and use it in GitHub Desktop.
Save allieus/01cdd091906f0f3653d57275aa70f288 to your computer and use it in GitHub Desktop.

TL;DR

django-subdomains 라이브러리는 channels websocket URL 라우팅에 관여할 수 없습니다.

배경

웹소켓에서도 urlpatterns를 지정하고 URL 별로 다른 Consumer를 지정할 수 있는데요. 서브도메인 별로 다른 urlpatterns를 가지도록 할 수 있느냐. 이를 위해 django-subdomains 라이브러리를 사용할 수 있느냐가 주제였습니다.

django-subdomains 라이브러리는 장고 미들웨어를 통해, 요청 도메인별로 root urlconf를 다르게 설정해주는 기능을 합니다. channels에서 django-subdomains이 사용가능하느냐인데요. 결론적으로는 django-subdomains는 channels를 지원할 수 없습니다.

asgi/channels를 통해 장고를 구동하게 되면, http/websocket 라우팅은 장고로 요청이 전달되기 전에 asgi 레벨에서 이뤄지므로, django-subdomains는 라우팅에 관여를 할 수 없게 됩니다.

그래서 channels의 ProtocolTypeRouter를 참고하여 SubdomainURLRouter를 간단히 만들어봤습니다. 그럼 도메인 별로 다른 websocket urlpatterns를 지정할 수 있게 됩니다.

from django.utils.encoding import smart_str
class SubdomainURLRouter:
def __init__(self, router_mapping):
self.router_mapping = router_mapping
async def __call__(self, scope, receive, send):
for name, value in scope.get("headers", []):
if name == b"host":
host = smart_str(value)
break
else:
host = None
if host is None:
raise ValueError("No host header")
else:
try:
app = self.router_mapping[host]
except KeyError:
raise KeyError("No router for host", host)
return await app(scope, receive, send)
application = ProtocolTypeRouter(
{
"http": get_asgi_application(),
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
SubdomainURLRouter(
{
"a.example.com": URLRouter(chat_websocket_urlpatterns),
}
),
),
),
}
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment