关于django中间件使用的踩坑经历

背景

??这个之前本地写的那个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错误。

当然官方贴心的给出了额外的建议:

  1. 使用serve()视图提供静态资源访问服务。
  2. 通过Nginx、Apache等代理静态资源。

而对于在生产环境下,官方更推荐的是第二种方法,原因无非就两个:

  1. django提供的serve()视图仅用于开发辅助使用,不适合生产使用。
  2. 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的框架知识,当然工作学习过程中踩到的坑能够分享,也是对自己另外的一种学习提升。

原文地址:https://blog.51cto.com/mbb97/2397647

时间: 2024-10-01 00:06:38

关于django中间件使用的踩坑经历的相关文章

.Net4.6 Task 异步OA现金盘平台出租函数 比 同步函数 慢5倍 踩坑经历

异步Task简单介绍本标题有点 哗众取宠OA现金盘平台出租QQ2952777280[话仙源码论坛]hxforum.com[木瓜源码论坛]papayabbs.com ,各位都别介意(不排除个人技术能力问题) -- 接下来:我将会用一个小Demo 把 本文思想阐述清楚. .Net 4.0 就有了 Task 函数 -- 异步编程模型 .Net 4.6 给 Task 增加了好几个 特别实用的方法,而且引入了 await async 语法糖 当然,这是非常不错的技术,奈何我有自己的线程队列封装,也就没有着

TiDB 深度实践之旅--真实“踩坑”经历

美团点评 TiDB 深度实践之旅(9000 字长文 / 真实“踩坑”经历) 4 PingCAP · 154 天前 · 3956 次点击 这是一个创建于 154 天前的主题,其中的信息可能已经有所发展或是发生改变. 原标题:美团点评携手 PingCAP 开启新一代数据库深度实践之旅 一.背景和现状 在美团,基于 MySQL 构建的传统关系型数据库服务已经难于支撑公司业务的爆发式增长,促使我们去探索更合理的数据存储方案和实践新的运维方式.随着近一两年来分布式数据库大放异彩,美团 DBA 团队联合架构

【踩坑经历】一次Asp.NET小网站部署踩坑和解决经历

2013年给1个大学的小客户部署过一个小型的Asp.NET网站,非常小,用的sqlite数据库,今年人家说要换台服务器,要重新部署一下,好吧,虽然早就过了服务时间,但无奈谁叫人家是客户了,二话不说,上,源代码和以前的文件都有,部署还不是分分钟的事情,打开IIS挂上去就行了.谁知道,这个部署将近花了2天的时间.看看踩坑过程和解决方法. 本文原文地址:http://www.cnblogs.com/asxinyu/p/4380380.html 1.居然拿XP系统做服务器 第一个坑其实和我没关系,客户以

Xamarin踩坑经历

1.SDK版本 Android SDK Build-tools必须安装23.0.1版,不得升级高版本,否则将导致异常:尝试在条件"$(_DeviceSdkVersion) >= 21"中对计算结果为""而不是数字的"$(_DeviceSdkVersion)"进行数值比较. 2.JDK JDK最好使用1.8版本,否则VS2017中的Xamarin项目编译会失败. 3.目标最低Android版本 在App.Droid项目属性中设置最低Andro

Uber使用Swift重写APP的踩坑经历及解决方案(转载)

我是托马斯·阿特曼,目前是Uber移动架构和框架组负责人.Uber现在的用户量已经达到数百万,这么大的用户量,Uber是如何用框架实现的呢? Swift与百位工程师的故事 - 原因.架构.经验 今天我想谈谈一百多名Uber工程师是如何使用Swift编程语言的,在上周三新发布的Rider App主应用程序全部都是用Swift语言重构的.接下来我的分享主要包括三个部分:选择Swift的原因.Uber新架构:重构经验. 优步的开端--重构的原因 这是整个移动团队四年前的样子(指向屏幕显示有三名工程师的

Mysql视图权限设置的踩坑经历

1.事件背景今天临近中午饭点时,开发同事发来需求,在mariadb库创建两个视图,要求指定帐号有只读权限.很简单的需求,连上服务器,两条grant命令一刷,fulsh privileges 回车,楼主就安心吃饭去了. 2.重点来了,待楼主用餐归来,(还在楼下打了盘王者农药,排位两连跪(┬_┬)),上午发来需求的同事找我了. 3.柳暗花明瞬间蒙圈的我,回了个稍等,就赶紧去查原因了.在反复确认grant没问题后,楼主持续蒙圈了.此时距离接到这个问题,已经过去了20分钟,甚是焦急啊,明明一个小需求怎么

【踩坑经历】SQLSTATE[HY000] [2002] Connection refused

使用docker搭建lnmp环境,使用的是分容器的搭建方案 框架使用thinkphp,想要连接数据MySQL,一直显示"SQLSTATE[HY000] [2002] Connection refused" 数据库配置host填的是localhost,后面改成了127.0.0.1,都是连接不了 还以为是数据库用户权限问题,新建了一个用户,刷新了权限,结果还是不行 想了好久,原来都是分容器的问题,由于采用了分容器的搭建方案,在php的容器内连接127.0.0.1或者localhost,肯定

Net core 2.x 升级 3.0 使用自带 System.Text.Json 时区 踩坑经历

.Net Core 3.0 更新的东西很多,这里就不多做解释了,官方和博园大佬写得很详细 关于 Net Core 时区问题,在 2.1 版本的时候,因为用的是 Newtonsoft.Json,配置比较方便 AddJsonOptions(opt => { opt.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local; }) 但是用 System.Text.Json 就没那么方便了,翻

记录 SpringBoot 踩坑经历

1.spring-boot-starter-web 作用 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 在使用 IDEA 每次自动创建项目的时候,都会自动加上以上依赖!但是你有没有仔细想过,为什么? 今天小司机带你开车,一探究竟.兄弟们,坐稳了