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,仍是能访问到页面的话,清理下浏览器的缓存,就能够了

相关文章
相关标签/搜索