장고에서 URL 패턴을 정의할 때 항상 끝에 /
가 오는 것을 볼 수 있다. 이를 트레일링 슬래시(trailing slash)라 부르는데, 이런 형식을 따르는 이유는 웹 서버 및 사용자 경험을 개선하기 위해서이다.
예전에는 트레일링 슬래시가 있으면 디렉토리, 없으면 파일을 의미했지만, 현재에는 라우팅과 데이터베이스로 데이터를 가져오기 때문에 URL과 디렉토리 구조가 직접적인 연관이 없다.
따라서 URL 패턴을 일관된 형식으로 유지함으로서 사용자에게 예측 가능한 링크를 제공한다. 예시 코드를 보면서 확인해보자.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('sign-up/', views.sign_up, name='sign-up'),
]
path를 통해 sign-up/
과 views의 sign_up
함수를 매핑하는 간단한 코드이다. URL 패턴의 뒤에 /
가 붙어있는 것을 볼 수 있다.
여기로 POST
요청과 GET
요청을 하는 클라이언트 코드를 보자.
<form class="form-area" method="post" action="/user/sign-up/">
{% csrf_token %}
<div class="form-group mt-2 mb-2">
<label for="username">이름</label>
<input type="text" class="form-control" id="username" name="username">
</div>
<div class="form-group mt-2 mb-2">
<label for="password">비밀번호</label>
<input type="password" class="form-control" id="password" name="password">
</div>
<hr>
<div style="float: right">
<button type="submit" class="btn btn-primary">회원가입</button>
<a href="/sign-in" class="btn btn-secondary">로그인 페이지로</a>
</div>
</form>
가장 위의 form
태그를 보자. /sign-up/
에 이름과 비밀번호를 담아 POST
요청을 보내고 있다. 여기서 마지막 /
를 반드시 명시해야 한다.
그렇다면 아래에 로그인 페이지로 연결된 a
태그를 보자. 이상하게도 여기에는 /sign-in
로 링크하고 있다. 실제로 사이트에 접속해보면 문제 없이 실행된다.
왜 이렇게 동작할까? 이것은 장고가 URL 요청을 처리하는 방식 때문이다.
장고에는 APPEND_SLASH
라는 옵션이 있다. 이 옵션은 URL의 마지막에 /
가 없을 경우 자동으로 /
를 붙인 경로로 리다이렉트한다. 따라서 페이지 이동이나 GET
으로 요청한 데이터는 URL자체에 모든 데이터가 들어 있기 때문에 리다이렉트 시 데이터가 유실되지 않는다.
하지만 POST
의 경우에는 리다이렉트 시 변경된 URL로 데이터가 전달되지 않으므로 폼 데이터가 삭제된다. 그래서 실제로 이러한 디버그 메시지를 볼 수 있다.
You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data.
이 URL로
POST
요청을 보냈지만 마지막 슬래시가 없다.APPEND_SLASH
설정이 되어 있지만 장고는POST
데이터를 유지하는 동안은 슬래시를 붙여 리다이렉트 할 수 없다.
따라서 POST
요청의 URL에는 반드시 마지막 슬래시를 붙여 주도록 하자.