内容简介:这个之前本地写的那个django测试项目说起,那时候写了个练手的项目,目的是为了起因是当我在自强学堂的django课堂上,看到了有一个demo,这个demo具体实现的效果就是当网站在正式环境上运行的时候,为了安全起见,将DEBUG改为False(关闭调试模式),但是导致网站发生错误无法查看错误详情。所以demo主要的就是写一个
背景
这个之前本地写的那个django测试项目说起,那时候写了个练手的项目,目的是为了 熟悉总结django2.0和django1.8的区别 。不试不知道,一试就发现了许许多多的坑以及bug,把这些坑以及bug解决完了之后,打算写篇文章记录下我遇到的问题以及解决方法和思路。
起因
起因是当我在自强学堂的django课堂上,看到了有一个demo,这个demo具体实现的效果就是当网站在正式环境上运行的时候,为了安全起见,将DEBUG改为False(关闭调试模式),但是导致网站发生错误无法查看错误详情。
所以demo主要的就是写一个 通过中间件识别身份 的方式,如果是管理员则可以看到 网站错误详情 ,如果是普通访问者或者游客则 返回的是简单的错误码 。
详细设计
设计思路
中间件识别登录身份,判断是否为管理员,如果是管理员的话,当网站出现错误的时候则会显示错误详情;如果是普通游客的话则单纯显示错误码,不显示详情。
关于中间件
我整理了一下有关django的中间件知识,这里大概聊一下,以后有机会单独的写篇文章总结一下。首先我们要明白什么是中间件:
这里先引用官方文档的一段话:
Middleware is a framework of hooks into Django’s request/response processing. It’s a light, low-level “plugin” system for globally altering Django’s input or output.
- 简而言之,Middleware就是能够修改Django中 response/request对象的钩子 ,我们可以利用Middleware来实现在请求到达 view视图函数 前的一些操作。
- 举个最简单的例子: 一个管理后台判断用户是否登录 ,就是判断 request对象中的用户 ,如果对象中的用户是不存在的,则重定向到登录页面。
中间件处理流程
大概了解了一下中间件是什么东西,可以用来做什么,我们大致分析一下中间件的处理流程。
相信上图在很多django教程中看到过,上图都是Django中内置的一些中间件,这些中间件都放在Django中 settings.py 文件中的 MIDDLEWARE_CLASSES 。 (django 2.0版本后放在MIDDLEWARES上)
然后在http请求阶段,在view调用之前了,django会将 MIDDLEWARE_CLASSES 中的中间件都执行一遍。而这里面的主要的几个钩子函数:
- process_request()、process_view() 会从上到下挨个执行一遍;
- process_exception()、process_template_response()、process_response() 则会从下到上挨个执行一遍。
具体这几个函数作用,以及django内置中间件分别负责什么作用单独会另外写篇文章总结。
这里的主要使用到 process_exception() 钩子,这个钩子函数只有当view抛出异常的时候会触发,所以很适合返回网站的错误详情。
具体实现
终于到实操环节了,思路上面提到过了,这里具体代码实现的逻辑:
用户通过登录界面登录到平台,通过内置的 auth模块 保存用户登录到会话中。
如果网站出现错误信息时,这时异常抛到自己的中间件时,捕获views视图函数抛出的异常,判断request中的user对象是否为超级管理员,如果是的话,则返回一个错误详细响应到前端,不是的话正常返回500错误码。
-
以下是views.py中关于用户登录模块,具体登录请求会提交到这里:
def login(request): if request.method == 'POST': user_name = request.POST['user_name'] user_password = request.POST['user_password'] user = auth.authenticate(username=user_name, password=user_password) if user is not None: auth.login(request, user) return redirect('/index') else: return render(request, 'login.html', {'login_error': '登录失败,密码>错误'}) return render(request, 'login.html')
- 中间件middleware.py具体代码(具体位置放在app应用下):
from django.views.debug import technical_500_response import sys class UserBasedExceptionMiddleware(object): def process_exception(self, request, exception): if request.user.is_superuser: return technical_500_response(request, *sys.exc_info())
- settings.py修改MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = [ 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', 'app.middleware.UserBasedExceptionMiddleware', ]
* 这样就能实现返回网站错误信息啦:
做到这里想必是做完了,但是我更想谈谈我在这过程遇到两个问题,在这两个问题里可能花费的时间更多。
遇到的问题
解决DEBUG=False下,静态资源访问出现404
由于将DEBUG模式设置 False 之后,重新启动项目后,发现所有的静态文件都无法访问。
查了一下官方文档,官方文档给出的解释就是,在开发过程中,django会提供 django.contrib.staticfiles 帮助管理静态文件,而开启这一功能,除了 需要包含在INSTALL_APPS之外 ,还需要将 DUBUG模式改为True 。
所以略微分析,大概就知道我们静态文件404访问不到的原因了,简单来说就是 django提供给我们的静态文件路由功能不能用了 ,导致404错误。
当然官方贴心的给出了额外的建议:
- 使用serve()视图提供静态资源访问服务。
- 通过Nginx、Apache等代理静态资源。
而对于在生产环境下,官方更推荐的是 第二种方法 ,原因无非就两个:
- django提供的serve()视图仅用于开发辅助使用,不适合生产使用。
- Nginx处理静态资源有着更强的性能优势。
解决过程
这里我们就先通过上面提到第一种方法来解决“静态资源404的问题”。
而关于Django和Nginx部署Django项目的,之前在一篇文章里介绍过,大家有兴趣可以去看看: https://blog.51cto.com/mbb97/2151933
- 解决这一问题其实很简单,直接修改 urls.py ,直接在 urlpatterns 列表下增加多一段代码,匹配静态资源请求路径,调用 django内置静态资源处理方法serve() ,大功告成。
from django.contrib import admin from django.views.static import serve from django.urls import path,re_path urlpatterns = [ path('admin/', admin.site.urls), ] if not settings.DEBUG: urlpatterns += [ re_path(r'^static/(?P<path>.*)$', serve, {'document_root': 'static', }), ]
* 重启django项目,大功告成,第一个问题解决
中间件不适配django2.0
我把这个中间件文件复制到另外一个项目中,打算一劳永逸,没想到竟然出错了:
首先我检查的就是 版本 的问题,我看了一下刚刚中间件成功的那个项目是属于 django1.8.2版 本,而如今报错的项目没想到是 django2.0 版本。
我查了官方文档,以下是官方文档的解释,有兴趣的可以了解以下:
https://docs.djangoproject.com/zh-hans/2.2/topics/http/middleware/
而参考官网给出的解决方法,就是通过Django提供的 django.utils.deprecation.MiddlewareMixin 类,它能够轻松兼容新版的 MIDDLEWARE和旧版的MIDDLEWARE_CLASSES 。
- 以下是示例代码,修改中间件能够轻松兼容Django新版本和旧版本:
from django.views.debug import technical_500_response import sys try: from django.utils.deprecation import MiddlewareMixin except: MiddlewareMixin = object class UserBasedExceptionMiddleware(MiddlewareMixin): def process_exception(self, request, exception): if request.user.is_superuser: return technical_500_response(request, *sys.exc_info())
-
重启项目,没有报错:
- 问题解决,管理员用户能够看到网站错误信息:
总结
没想到一个小小的中间件功能实现竟然途中遇到了这么多问题,但是在遇到问题的过程中排查问题的方向都是大致正确的,说起不足的地方还是对于Django的整体框架知识不够扎实。
由于Django上很多东西都是等到需要用的时候,才会去查找资料,这也导致很多问题不能第一时间反应解决。所以对 于Django新版本和旧版本之间的区别 没有及时的整理,以及 类似中间件重要的知识点 没有及时归纳。
以后尽量抽时间整理一下Django的框架知识,当然工作学习过程中踩到的坑能够分享,也是对自己另外的一种学习提升。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。