python-django中的APPEND_SLASH實現

關於django中的APPEND_SLASH

APPEND_SLASH 它是啥?前端

看變量名大概能知道作什麼,就是添加斜線,用路由系統那裏。python

路由文件,只寫了路由關係代碼django

......
urlpatterns = [
    url(r'^test/$', views.test),
]
......

APPEND_SLASH這個常量默認爲True,就是假如你沒有添加斜線,他會幫你添加上(整體是這樣,具體得看源碼怎麼寫的了)瀏覽器

執行命名行代碼啓動django項目緩存

python manage.py runserver

目前APPEND_SLASH=True,咱們打開瀏覽器的開發者工具,查看網絡請求,輸入127.0.0.1:8000/test 這裏我是沒有加斜線的服務器

仔細看下網絡請求,咱們輸入127.0.0.1:8000/test,看起來只發送了一次,其實真實發送了兩次請求。網絡

咱們繼續再訪問這個url:127.0.0.1:8000/test11,看看請求app

咱們也一樣訪問了一個url,可是此次和上面不一樣的是,只發送了一次請求。工具

兩次都是發送一個get請求,訪問服務器的一個資源。url

第一次請求的url爲127.0.0.1:8000/test,咱們的路由關係中是沒有這個url的,對沒錯,若是訪問想要訪問到服務器的資源必須爲這樣的url才行127.0.0.1:8000/test/,雖然說這兩個url看起來差很少,但其實差不少的。可是第一次請求的url只需在最後加上/,就能訪問到資源了,這就是APPEND_SLASH的做用。

第二次請求的url爲127.0.0.1:8000/test11,這個地址也不在咱們的路由關係中,何況加上了/,也不能訪問到資源。因此總共發送了一次,最終返回了404錯誤。

先大體總結下:APPEND_SLASH=True的狀況下,先會根據前端傳來的url,先檢測這個url能不能訪問資源,若是能夠訪問的話,那麼就去執行相應的業務代碼,最後返回。若是這個url不能訪問到資源的話,會判斷這個url最後有沒有/,有/的話,則返回404錯誤;若是沒有/的話,便會幫你加上/,生成一個新的url,再去檢測這個新的url能不能訪問到資源,若是能訪問的話,則返回301的狀態碼,並將這個新的url傳到前端,進行重定向操做(這就是咱們第一次請求出現的狀況),若是這個新的url(幫你加上/的)仍是不能訪問到資源的話,也會返回404錯誤(這就是咱們第二次請求出現的狀況)。這就是對上面出現狀況的總結吧(具體流程還得去看源碼)

那麼APPEND_SLASH=False的狀況,就不會幫你加/,你前臺傳怎樣的url,那就用這個url去訪問資源,能不能訪問還得看你url對不對。

在走到路由層以前,請求會先走到中間件這一層,在這一層就執行了上面分析的邏輯

這一個中間件實現了上面的邏輯 'django.middleware.common.CommonMiddleware',請求來的時候,會走這個中間件的process_request方法,下面來看這個方法寫了什麼

看這一句註釋:# Check if a slash should be appended,檢測是否須要加上斜線

看這個方法should_redirect_with_slash,返回值爲bool類型。返回True的狀況是,APPEND_SLASH=True,這個url不是以/結尾的,而且這個url添加上了/,可以訪問資源的。必須知足這三種狀況,返回值爲True,其餘狀況的話返回就是False。

下面貼上should_redirect_with_slash的源碼

def should_redirect_with_slash(self, request):
    """
    Return True if settings.APPEND_SLASH is True and appending a slash to
    the request path turns an invalid path into a valid one.
    """
    if settings.APPEND_SLASH and not request.path_info.endswith('/'):
        urlconf = getattr(request, 'urlconf', None)
        return (
            not is_valid_path(request.path_info, urlconf) and
            is_valid_path('%s/' % request.path_info, urlconf)
        )
    return False

就說下 is_valid_path方法有啥做用吧。你能夠去看源碼具體瞭解

is_valid_path 檢測傳進去的url,是否能訪問到資源。(說白了就是判斷這個url是否存在咱們定義的url映射中)

這樣的話,上面這段代碼就很簡單了。首先判斷APPEND_SLASH,若是爲False的。那麼這個方法should_redirect_with_slash直接返回False。若是APPEND_SLASH爲True的話,再對請求的url進行判斷,request.path_info它的值並非一個完整的url,而是ip+端口後面的那一部分(也就是例子中的/test),判斷它是否以斜線(/)結尾的,若是是的話,那麼not request.path_info.endswith('/') 總體就爲False,因此if判斷後面的表達式就爲False,最終返回了False。若是不是以斜線(/)結尾的話,那麼if後面的表達式就爲True,那麼繼續執行條件爲真的代碼塊,這個代碼塊最終返回了一個表達式的結果,這個表達式類型是這樣 bool and bool。也就是根據方法is_valid_pathd的返回值進行判斷的,若是request.path_info(代碼能分析到這裏說明它不是以斜線結尾的),首先判斷這個值能不能在咱們寫的路由關係映射中存不存在。存在的話,方法is_valid_path返回真,那麼not True就爲False,and左邊的表達式爲False,總體的表達式就爲False,因此最終返回的就是False。若是request.path_info的值在路由關係映射中不存在,那麼and左邊的表達式爲True,那就繼續看and右邊表達式的布爾值。and右邊仍是調用了方法is_valid_path,只不過傳的參數是request.path_info + /,若是在路由映射中存在,那麼最終返回True,若是不存在,那麼就返回了False了。

should_redirect_with_slash方法分析完畢,繼續看源碼

# Check if a slash should be appended
if self.should_redirect_with_slash(request):
    path = self.get_full_path_with_slash(request)
else:
    path = request.get_full_path()

後面根據should_redirect_with_slash方法的返回值,作了不一樣的操做。不嚴格來講,無論True仍是False,最終執行了requests.get_full_path這個方法,只不過傳入的參數不一樣的,最終返回了一個完整的url請求地址。

繼續往下看

# Return a redirect if necessary
if redirect_url or path != request.get_full_path():
    redirect_url += path
    return self.response_redirect_class(redirect_url)

若是if後面的表達式爲True的話,最終稿返回了一個狀態碼爲301的Httpresponse對象,這個對象裏帶這一個數據,這個數據就是在原url基礎上加上斜線(/)的新url,前端接收到狀態碼爲301的響應,則會繼續請求響應中攜帶的新地址。爲False的話,返回默認返回None。

django的中間件會根據每一箇中間件裏的process_request方法或者process_response方法不一樣的返回值會執行相應的操做,具體操做不說了,不是這個知識點的內容。

那麼中間件的process_request返回None的話,則會執行下一個中間件的process_request的方法。若是返回的是HttpResponse對象的話,則不會繼續執行下一個中間件的process_request方法,則會執行process_response方法。具體從哪一個中間件執行和django的版本有關係,反正是不會執行路由對應的視圖代碼的代碼,會直接返回給前端HttpResoonse對象。

好了,關於APPEND_SLASH的知識總結完畢。APPEND_SLASH它默認爲True,若是想要修改的話,須要在settings.py文件中定義這個常量,賦值爲False,這樣就能夠覆蓋原django中配置文件裏對應的常量了。至於django內部怎麼操做的,下次再總結吧

最後仍是補個圖吧,我把APPEND_SLASH設置爲False,訪問127.0.0.1:8000/test

若是你設置了APPEND_SLASH爲False,訪問上面這個url,仍是能訪問到頁面的話,清理下瀏覽器的緩存,就能夠了

相關文章
相關標籤/搜索