背景
?? 这个之前本地写的那个 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 版本.
? 我查了官方文档, 以下是官方文档的解释, 有兴趣的可以了解以下:
?
? 而参考官网给出的解决方法, 就是通过 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 的框架知识, 当然工作学习过程中踩到的坑能够分享, 也是对自己另外的一种学习提升.
来源: http://www.bubuko.com/infodetail-3066525.html